[考试反思]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 }
View Code

 

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 }
View Code

 

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 }
45pts

复杂度瓶颈在于里面$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 }
View Code

 

posted @ 2020-03-04 07:28  DeepinC  阅读(...)  评论(...编辑  收藏