[考试反思]0303省选模拟36:反常
我并没有咕博客啊模拟测试的编号突然跳了一个我也不知道为啥。
这场依旧没啥好说的。
$T1$大概是联赛难度了。。。模拟?不好说。
太简朴反而容易让人想复杂。我都不知道想到哪里去了幸亏最后收住了。
然后$T2$卡了一下常数所以比没卡的多了4分。
然而$T3$写炸了,常数过大被卡成成$5$分。
大体发挥正常吧。
$T2$思路挺奇妙的,想不到。
但是$T3$考后也没太看明白,多项式的奇怪扩展,还得花时间回头弄它。。
T1:Alchemy
大意:给定$hanoi$局面。判断它是最优解的第几步。$n \le 50$
模拟?就挨个判断每个盘子在哪里就好了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int p[55],t,n,ok; 4 long long sch(int x,int f,int t,int e){ 5 if(!x)return 0; 6 if(p[x]==e)return ok=0; 7 if(p[x]==f)return 1ll<<x-1|sch(x-1,f,e,t); 8 if(p[x]==t)return sch(x-1,e,t,f); 9 } 10 int main(){ 11 cin>>t;while(t--){ 12 ok=1;n=0; 13 for(int i=0,k,x;i<3;++i){ 14 scanf("%d",&k);n+=k; 15 while(k--)scanf("%d",&x),p[x]=i; 16 } 17 long long r=sch(n,0,2,1); 18 if(ok)cout<<r<<endl;else puts("No"); 19 } 20 }
T2:Algebra
大意:求大于等于$n$的最小的满足在$a,b$进制下每位的和相等的数。$n \le 10^{16},a,b, \le 36$
设一个$next(n,k,s)$表示大于等于$n$的最小的$k$进制下和为$s$的数。这个可以逐位贪心。
然后我们用一个类似最短路的方法把所有的$(n,s)pair$扔进堆里。每次取出一个扩展。
如果$next(n,a,s)=next(n,b,s)=n$那么就可以输出答案了。否则将$(max(next(n,a,s),next(n,b,s)),s)$丢进去。
最终的答案是$O(n)$级别的所以可以说明有效的$s$最大也就$400$左右
由于进位这种操作所以$next(a)$与$next(b)$交错分布的规律是随机的。而根据生日悖论,$next$的调用次数只有$O(\sqrt{n})$次。
而且常数比较小所以可以通过。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 struct x{ 5 ll n;int s; 6 friend bool operator<(x a,x b){return a.n>b.n;} 7 };priority_queue<x>q; 8 int mxt[38],bit[65],b[65];ll pw[38][65]; 9 bool chk(int al,int k,int s){ 10 for(int i=al;~i;--i)b[i]=0; 11 int p=al; 12 while(s>=k-1){ 13 if(bit[p]<k-1)return 1; 14 b[p]=k-1,p--,s-=k-1; 15 } 16 b[p]=s;if(s>bit[p])return 1;else if(s<bit[p])return 0; 17 for(int i=p;~i;--i)if(b[i]>bit[i])return 1;else if(b[i]<bit[i])return 0; 18 return 1; 19 } 20 ll sch(int al,int k,int s,int lim=1){ 21 if(al==-1)return 0; 22 for(int x=max(lim?bit[al]:0,s-(k-1)*al);x<k&&x<=s;++x)if(!lim||x>bit[al]||chk(al-1,k,s-x)) 23 return sch(al-1,k,s-x,lim&x==bit[al])+pw[k][al]*x; 24 return 1ll<<62; 25 } 26 ll nxt(ll n,int k,int s){ 27 for(int i=0;i<65;++i)bit[i]=0; 28 int cnt=0; 29 while(n)bit[cnt]=n%k,n/=k,cnt++; 30 return sch(mxt[k]-1,k,s); 31 } 32 int main(){ 33 for(int i=2;i<37;++i){ 34 pw[i][0]=1; 35 while(pw[i][mxt[i]]<1ll<<55)++mxt[i],pw[i][mxt[i]]=pw[i][mxt[i]-1]*i; 36 ++mxt[i],pw[i][mxt[i]]=pw[i][mxt[i]-1]*i; 37 } 38 int t;cin>>t;while(t--){ 39 ll n;int a,b,s;cin>>n>>a>>b; 40 for(int s=0;s<400;++s)q.push((x){n,s}); 41 while(1){ 42 n=q.top().n;s=q.top().s;q.pop(); 43 ll A=nxt(n,a,s),B=nxt(n,b,s); 44 if(A==B&&A==n){cout<<n<<endl;goto E;} 45 q.push((x){max(A,B),s}); 46 }E:;while(!q.empty())q.pop(); 47 } 48 }
T3:Anarchy
大意:高维多项式卷积。$n=\prod times_i \le 10^5$
大概意思是,我们需要构造一种$DFT$使之满足:
设$i,j,y$为两个高维向量。那么$ans_y = \sum\limits_{i + j = y} x_i \times y_j$
其中条件中的加号,是模意义下,每一维都相等。
发现这个条件,只需要依次对每一维都做一遍循环卷积的$DFT$就好了。
最低维显然成立,更高维只是将数替换成了序列,是一样的。对每一维分别做就可以了。
所以就可以做$DFT$了。这样的复杂度是$O(n\sum times_i)$的。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define S 333333 4 int n,m,Q,s[22]; double A,rt[S]; 5 struct cp{double r,i; 6 cp(){} cp(double a,double b):r(a),i(b){} 7 cp operator*(cp x){return cp(r*x.r-i*x.i,r*x.i+i*x.r);} 8 cp operator+(cp x){return cp(r+x.r,i+x.i);} 9 }a[S],d[S],t[S],T[S]; vector<cp>w[2][22]; 10 void FFT(int o,int op){ 11 for(int i=0;T[i]=cp(0,0),i<s[o];++i)for(int j=0;j<s[o];++j)T[i]=T[i]+w[op][o][i*j%s[o]]*t[j]; 12 if(!op)for(int i=0;i<s[o];++i)T[i].r/=s[o],T[i].i/=s[o]; 13 } 14 void DFT(cp*a,int op=1){ 15 for(int i=1,r=1;i<=m;r*=s[i],++i)for(int j=0;j<n;j+=r*s[i])for(int k=0;k<r;++k){ 16 for(int l=0;l<s[i];++l)t[l]=a[j+k+l*r]; 17 FFT(i,op); 18 for(int l=0;l<s[i];++l)a[j+k+l*r]=T[l]; 19 } 20 } 21 int main(){ 22 cin>>Q;while(Q--){ 23 cin>>m; n=1; 24 for(int i=1;i<=m;++i)cin>>s[i],n*=s[i],w[1][i].resize(s[i]),w[0][i].resize(s[i]); 25 for(int i=1;i<=m;++i)for(int j=0;j<s[i];++j) A=2*acos(-1)/s[i]*j,w[0][i][j]=cp(cos(A),sin(-A)),w[1][i][j]=cp(cos(A),sin(A)); 26 for(int i=0;i<n;++i)d[i]=cp(1,0),scanf("%lf",&a[i].r),a[i].i=0; 27 for(int i=1;i<=n;++i)rt[i]=pow(i,2./m); 28 for(int i=0,x;x=i,i<n;++i)for(int j=1;j<=m;++j)d[i].r*=rt[x%s[j]+1],x/=s[j]; 29 DFT(a);DFT(d); for(int i=0;i<n;++i)a[i]=a[i]*d[i]; DFT(a,0); 30 for(int i=0;i<n;++i)rt[i]=a[i].r; sort(rt,rt+n); 31 for(int i=n-1;i>n-101&&~i;--i)printf("%.9lf ",rt[i]/2/m);puts(""); 32 } 33 }
复杂度瓶颈在于里面$DFT$那里。我们一次$DFT$是得到$A_i = \sum\limits_{j=0}^{times_x-1} w_{times_x}^{ij} B_j$
然后这个$ij$非常难办,于是转化成别的形式,$ij=\frac{(i+j)^2-i^2-j^2}{2}$
把这坨东西大概代回去大概能得到$w_{times_x}^{-\frac{i^2}{2}} A_i = \sum\limits_{j=0}^{times_x-1} B_j w_{times_x}^{-\frac{j^2}{2}} w_{times_x}^{\frac{(i+j)^2}{2}}$
一个经典的减法卷积。也没有长度或者循环什么的限制,于是直接做一个经典的$FFT$就可以了。
然而其实可以利用一下循环卷积,我做题少第一次见:减法卷积平时都会翻转于是按照含义来说低位上是没有数的。
所以这时候我们不用开长长度直接让它循环卷下来就好了,长度可以开$2n$而不用$3n$。
然而这次没有写。这道题还卡常,所以对于长度比较小的时候还是暴力卷积。总时间复杂度是$nlog^2n$
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define S 2222222 4 int n,m,Q,s[22],len,rev[S]; double A,rt[S]; 5 struct cp{double r,i; 6 cp(){} cp(double a,double b):r(a),i(b){} 7 cp operator*(cp x){return cp(r*x.r-i*x.i,r*x.i+i*x.r);} 8 cp operator+(cp x){return cp(r+x.r,i+x.i);} 9 cp operator-(cp x){return cp(r-x.r,i-x.i);} 10 }a[S],d[S],t[S],T[S],r[S],x,y; vector<cp>w[2][22],W[2][22]; 11 void fft(cp*a,int op=1){ 12 for(int i=1;i<len;++i)if(rev[i]>i)swap(a[i],a[rev[i]]); 13 for(int i=1,c=1;i<len;i<<=1,++c)for(int j=0;j<len;j+=i<<1)for(int k=0;k<i;++k) 14 x=a[k+j],y=a[k+j+i]*W[op][c][k],a[j+k]=x+y,a[j+k+i]=x-y; 15 if(!op)for(int i=0;i<len;++i)a[i].r/=len,a[i].i/=len; 16 } 17 void FFT(int o,int op){ 18 if(s[o]<64) for(int i=0;T[i]=cp(0,0),i<s[o];++i)for(int j=0;j<s[o];++j)T[i]=T[i]+w[op][o][2ll*i*j%(2*s[o])]*t[j]; 19 else{ 20 len=1;while(len<s[o]*3)len<<=1; 21 for(int i=0;i<len;++i)rev[i]=rev[i>>1]>>1|(i&1?len>>1:0),T[i]=cp(0,0); 22 for(int i=0;i<s[o];++i)t[i]=t[i]*w[op^1][o][1ll*i*i%(2*s[o])]; 23 for(int i=s[o];i<len;++i)t[i]=cp(0,0); 24 reverse(t,t+s[o]); 25 for(int i=0;i<s[o]*2;++i)T[i]=w[op][o][1ll*i*i%(2*s[o])]; 26 fft(t);fft(T);for(int i=0;i<len;++i)T[i]=T[i]*t[i];fft(T,0); 27 for(int i=0;i<s[o];++i)T[i]=T[i+s[o]-1]*w[op^1][o][1ll*i*i%(2*s[o])]; 28 }if(!op)for(int i=0;i<s[o];++i)T[i].r/=s[o],T[i].i/=s[o]; 29 } 30 void DFT(cp*a,int op=1){ 31 for(int i=1,r=1;i<=m;r*=s[i],++i)for(int j=0;j<n;j+=r*s[i])for(int k=0;k<r;++k){ 32 for(int l=0;l<s[i];++l)t[l]=a[j+k+l*r]; 33 FFT(i,op); 34 for(int l=0;l<s[i];++l)a[j+k+l*r]=T[l]; 35 } 36 } 37 int main(){ 38 for(int i=0;i<=21;++i)W[0][i].resize(1<<i),W[1][i].resize(1<<i); 39 for(int i=0;i<=21;++i)for(int j=0;j<1<<i;++j) A=2*acos(-1)/(1<<i)*j,W[0][i][j]=cp(cos(A),sin(-A)),W[1][i][j]=cp(cos(A),sin(A)); 40 cin>>Q;while(Q--){ 41 cin>>m; n=1; 42 for(int i=1;i<=m;++i)cin>>s[i],n*=s[i],w[1][i].resize(s[i]<<1),w[0][i].resize(s[i]<<1); 43 for(int i=1;i<=m;++i)for(int j=0;j<s[i]<<1;++j) A=acos(-1)/s[i]*j,w[0][i][j]=cp(cos(A),sin(-A)),w[1][i][j]=cp(cos(A),sin(A)); 44 for(int i=0;i<n;++i)d[i]=cp(1,0),scanf("%lf",&a[i].r),a[i].i=0; 45 for(int i=1;i<=n;++i)rt[i]=pow(i,2./m); 46 for(int i=0,x;x=i,i<n;++i)for(int j=1;j<=m;++j)d[i].r*=rt[x%s[j]+1],x/=s[j]; 47 DFT(a);DFT(d); for(int i=0;i<n;++i)a[i]=a[i]*d[i]; DFT(a,0); 48 for(int i=0;i<n;++i)rt[i]=a[i].r; sort(rt,rt+n); 49 for(int i=n-1;i>n-101&&~i;--i)printf("%.9lf ",rt[i]/2/m);puts(""); 50 } 51 }