码迷,mamicode.com
首页 > 其他好文 > 详细

[考试反思]0118省选模拟11:迟缓

时间:2020-01-19 09:48:46      阅读:106      评论:0      收藏:0      [点我收藏+]

标签:平衡树   com   昨天   方法   init   insert   lin   后缀   ++i   

技术图片

技术图片

Flag:下次AKt再半夜3点打呼噜给我弄醒我就下床拿枕头捶醒他

困死了啊啊啊啊啊啊啊

状态极差,写了三个暴力,根本没动脑子,也不想动,也不能动

所以就在考场上把昨天T2给水过了

 

 

T1:组合数问题

题意:给定$n$个数从中任意选子集乘积不超过$k$的方案数。

正解还不会,但是记录一些搜索剪枝的技巧。

预先排序肯定是要有的。相同元素压在i一起,特殊考虑特殊元素(如1以及大于根号的)

预处理$lower \ bound$值,及时返回跳出,以及搜索顺序的问题。

然而我的搜索还是不很优。。。虽说我感觉和正解有那么一点点相像

但是完全看不懂正解,鸽了

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define mod 998244353
 4 map<int,int>r;unordered_map<int,int>dp[222222];
 5 int n,k,s[222222],t[222222],lwb[22222222],fac[222222],inv[2222222],cnt1;
 6 int qp(int b,int t,int a=1){for(;t;t>>=1,b=1ll*b*b%mod)if(t&1)a=1ll*a*b%mod;return a;}
 7 int C(int b,int t){return 1ll*fac[b]*inv[t]%mod*inv[b-t]%mod;}
 8 int sch(int n,int k){
 9     if(n==0||k<s[1])return 1;
10     if(k<=20000000&&n>lwb[k])n=lwb[k];
11     if(dp[n].find(k)!=dp[n].end())return dp[n][k];
12     int rk=k,ans=0;
13     for(int c=0;c<=t[n]&&rk;++c,rk/=s[n])ans=(ans+1ll*sch(n-1,rk)*C(t[n],c))%mod;
14     return dp[n][k]=ans;
15 }
16 int main(){
17     cin>>n>>k;
18     fac[0]=1; for(int i=1;i<=200000;++i)fac[i]=1ll*fac[i-1]*i%mod;
19     inv[200000]=qp(fac[200000],mod-2);
20     for(int i=199999;~i;--i)inv[i]=inv[i+1]*(i+1ll)%mod;
21     for(int i=1,x;i<=n;++i){scanf("%d",&x);if(x==1)cnt1++;else r[x]++;}
22     n=0;for(auto it:r)s[++n]=it.first,t[n]=it.second;
23     for(int i=1;i<=n;++i){
24         long long x=1;
25         for(int j=1;j<=t[i];++j){x*=s[i];if(x>k)t[i]=j-1;break;}
26     }
27     for(int i=1;i<=n&&s[i]<=20000000;++i)lwb[s[i]]=i;
28     for(int i=1;i<=20000000;++i)if(!lwb[i])lwb[i]=lwb[i-1];
29     cout<<1ll*sch(n,k)*qp(2,cnt1)%mod<<endl;
30 }
View Code

 

T2:recollection

大意:给定前缀trie,求$max(lcs+lcp)$。$m \le 200000$

既然已经是前缀$trie$了那么$lcp$就已经是$dep_{lca}$了。

字符串题,要求$lcs$,既然是后缀那就上$SAM$呗。

勉强算一个广义,这道题可以按照$dfs$建树然而复杂度不对。。。

现在问题就是给你两棵树求最大的$lca$深度和的点对。

对于其中一棵树按照$dfn$排个序的话所有的$lca$都是相邻两点的$lca$。距离越近$lca$越深。

这时候我们在另一棵树上$dfs$,每个点最初只有自己这个节点,线段树合并维护子树和,维护信息时顺便$ST$表查询最优的$lca$

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define S 400004
 4 unordered_map<int,int>c[S];
 5 int pc=1,f[S],len[S],lst=1,ans,n;
 6 int extend(int C){
 7     int p=lst,np=lst=++pc,q,nq; len[np]=len[p]+1;
 8     for(;p&&!c[p][C];p=f[p])c[p][C]=np;
 9     if(!p)return f[np]=1,lst;
10     if(len[q=c[p][C]]==len[p]+1)return f[np]=q,lst;
11     nq=++pc; len[nq]=len[p]+1; c[nq]=c[q];
12     f[nq]=f[q]; f[q]=f[np]=nq;
13     for(;c[p][C]==q;p=f[p])c[p][C]=nq;
14     return lst;
15 }
16 int l[S],to[S],v[S],ec,fir[S],dfn[S],t,eu[S],dep[S],rp[S],Rp[S];
17 void link(int a,int b,int w){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;v[ec]=w;}
18 void dfs(int p,int nc){
19     int tp=rp[p]=p==1?1:extend(nc); eu[++t]=p; dfn[p]=t;
20     for(int i=fir[p];i;i=l[i])lst=tp,dep[to[i]]=dep[p]+1,dfs(to[i],v[i]),eu[++t]=p;
21 }
22 int ST[20][S],lb[S],ref[S];
23 void ST_init(){
24     for(int i=1;i<=t;++i)ST[0][i]=dep[eu[i]];
25     for(int i=1;i<20;++i)for(int j=1<<i;j<1<<i+1&&j<S;++j)lb[j]=i;
26     for(int i=1;i<20;++i)for(int j=1;j+(1<<i)-1<=t;++j)
27         ST[i][j]=min(ST[i-1][j],ST[i-1][j+(1<<i-1)]);
28 }
29 int deplca(int x,int y){
30     if(y<x)swap(x,y);
31     int B=lb[y-x+1];
32     return min(ST[B][x],ST[B][y-(1<<B)+1]);
33 }
34 int Fir[S],La[S],To[S],Ec,rt[S],lc[S<<5],rc[S<<5],L[S<<5],R[S<<5],w[S<<5],spc;
35 void Link(int a,int b){La[++Ec]=Fir[a];Fir[a]=Ec;To[Ec]=b;}
36 #define md (cl+cr>>1)
37 void insert(int&p,int v,int cl=1,int cr=t){
38     p=++spc;L[p]=R[p]=v;
39     if(cl==cr)return;
40     if(v<=md)insert(lc[p],v,cl,md);else insert(rc[p],v,md+1,cr);
41 }
42 void merge(int&p,int cp,int cl=1,int cr=t){
43     if(!cp)return;
44     if(!p){p=cp;return;}
45     merge(lc[p],lc[cp],cl,md);merge(rc[p],rc[cp],md+1,cr);
46     if(!lc[p])L[p]=L[rc[p]],R[p]=R[rc[p]],w[p]=w[rc[p]];
47     else if(!rc[p])L[p]=L[lc[p]],R[p]=R[lc[p]],w[p]=w[lc[p]];
48     else L[p]=L[lc[p]],R[p]=R[rc[p]],w[p]=max(w[lc[p]],max(w[rc[p]],deplca(R[lc[p]],L[rc[p]])));
49 }
50 void Dfs(int p){
51     if(Rp[p])insert(rt[p],dfn[Rp[p]]);
52     for(int i=Fir[p];i;i=La[i])Dfs(To[i]),merge(rt[p],rt[To[i]]);
53     ans=max(ans,len[p]+w[rt[p]]);
54 }
55 int main(){
56     cin>>n;
57     for(int i=2,a,x;i<=n;++i)scanf("%d%d",&a,&x),link(a,i,x);
58     dfs(1,0);ST_init();
59     for(int i=1;i<=t;++i)Rp[rp[i]]=i;
60     for(int i=2;i<=pc;++i)Link(f[i],i);
61     Dfs(1);cout<<ans<<endl;
62 }
View Code

 

T3:comparision

大意:给定两个二元组(0,0),(n+1,n+1)。0可以分裂为(0,0),n+1同理。每次操作将两个已有集分别作为两关键字加入,求新集合在所有已有集中的排名。

$n \le 50000$

直觉:插入,查排名。像是平衡树,但是不敢写,然而其实也没有那么难写。

每次插入前二分新集合的排名,找到排名为$mid$的元素把它$splay$上来,分别比较它的两个元素和新集合的两个元素。

比较的方法也很草率。只要分别找到两个集合的排名就好。这个排名是在$splay$上动态维护的。

如果有多个完全一样的集合,我把它们都合并了。

记录一下每个集合对应$splay$上的哪一个节点(方便把它直接$splay$到根)

也记录一下$splay$上每个节点的代表元素,如果有多个随便记一个(方便获知它的两个元素进行比较)

然后就剩个$splay$上查排名对应的数了。写单旋没被卡。

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define S 55555
 4 int tp[S],a[S],b[S],n,sz[S],pc,val[S],c[2][S],f[S],rt,A[S],B[S];
 5 void up(int p){sz[p]=sz[c[0][p]]+sz[c[1][p]]+val[p];}
 6 void spin(int p){
 7     int F=f[p],G=f[F],D=c[1][F]==p,B=c[!D][p];
 8     if(G)c[c[1][G]==F][G]=p; c[!D][p]=F; c[D][F]=B;
 9     if(B)f[B]=F; f[f[F]=p]=G; up(F);
10 }
11 void splay(int p){for(int F;F=f[p];spin(p));up(rt=p);}
12 #define lc c[0][p]
13 void find(int p,int rk){
14     if(rk<=sz[lc])find(lc,rk);
15     else if(rk<=sz[lc]+val[p])splay(p);
16     else find(c[1][p],rk-sz[lc]-val[p]);
17 }
18 int Rank(int p){splay(tp[p]);return val[rt]+sz[c[0][rt]];}
19 bool cmp(int rk,int Ra,int Rb){
20     find(rt,rk);int ra=A[rt],rb=B[rt];ra=Rank(ra);
21     return ra!=Ra?ra<Ra:Rank(rb)<=Rb;
22 }
23 int main(){//freopen("1.in","r",stdin);
24     cin>>n; rt=2; pc=2;
25     tp[a[n+2]=b[n+2]=A[2]=B[2]=n+2]=2; tp[a[n+1]=b[n+1]=A[1]=B[1]=n+1]=1;
26     val[1]=val[2]=1; c[1][2]=1; f[1]=2; up(1); up(2);
27     for(int i=1;i<=n;++i){
28         scanf("%d%d",&a[i],&b[i]);
29         if(!a[i])a[i]=n+2;if(!b[i])b[i]=n+2;
30         int l=1,r=i+1,ans,ra=Rank(a[i]),rb=Rank(b[i]),rp;
31         while(l<=r)if(cmp(l+r>>1,ra,rb))l=ans=l+r>>1,l++;
32             else r=(l+r>>1)-1;
33         find(rt,ans);
34         int Ra=A[rt],Rb=B[rt];Ra=Rank(Ra);Rb=Rank(Rb);
35         find(rt,ans);
36         if(Ra==ra&&Rb==rb)val[rt]++,up(rt),tp[i]=rt;
37         else rp=c[1][rt],c[1][rt]=++pc,f[pc]=rt,c[1][pc]=rp,f[rp]=pc,val[pc]=1,A[pc]=a[i],B[pc]=b[i],tp[i]=pc,up(pc),up(rt);
38         printf("%d\n",Rank(i));
39     }
40 }
View Code

.

[考试反思]0118省选模拟11:迟缓

标签:平衡树   com   昨天   方法   init   insert   lin   后缀   ++i   

原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12210356.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!