这回真的是大众分了。肯定是不行的。。。联赛分已经比别人低了靠大众分不可能翻盘。
还指望着省选翻盘的话,肯定不能止步于此。
但是的确还是没有把能打的打满,T1被无良卡常了,最后才发现,来不及改了。
T1是比较明显的,大概算了一下复杂度没问题就写了。然而并没有自测大数据。
最后10分钟的时候想起来了,测了一下发现有点慢,疯狂加预处理,结果输出变了一慌没敢交。
然而事实上原输出不对而新输出对。。。所以手里攥着20分硬是没交(又想起了联赛。。。)
T2想骗分,故意开大模数尝试骗过$k=2$的点,然而出题人并没有留这种数据,于是浪费了很长时间分数没有变。
T3一眼看上去这不是多点求值模板题吗?数据范围更小了时限更大了,但是模数不好要写MTT。
开始回忆怎么构造。。。想了半天没想出来。。。弃了
着手暴力瞬间想起luogu第一篇题解:可以秦九韶暴力展开实测可以AC。
但是因为是乱搞所以没有仔细看,忘记了怎么写,发现复杂度主要在取模上但是不知道怎么减少次数。
最后虽说常数的确比不少人小,但是还是一分都没有多。
还是挺长记性的一次考试:
不要认为哪个知识点没用指不定那天就抡上来一道模板题(只不过不是正解?)
不要认为哪个小技巧没用指不定那天就抡上来一道卡常题(只不过比正解好写?)
不要认为哪个数据点可以钻出题人说不留分可能真的就是不留分了
而且一定要养成良好的卡常习惯,别的放一边,取模必须少!!!
(实测T3我的暴力带取模75s去掉取模其余不变只剩下1.9s)
T1:B
题目大意:求值域为n长度为k的不下降且最大公约数为1的数列个数。
$T le 5,k le 1000,n le 10^9,mod=10^9+7$
反演一下就去掉了公约数的限制,整除分块一下杜教筛莫比乌斯函数前缀和就行。问题就是怎么快速求方案数。
在数列开头加一个1在结尾加一个n就发现问题变成k次上涨可以为0恰好上涨n-1的方案数。挡板法,组合数。
因为$k$很小所以组合数直接暴力乘,复杂度是$O(k)$的。理论可过。
但是因为多测或什么的会被卡,小范围的需要预处理。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mod 1000000007 4 const int M=25000000; 5 int p[M>>2],pc,mu[M],iv[1111],fac[M];char np[M]; 6 unordered_map<int,int>Mu; 7 int MU(int x){ 8 if(x<M)return mu[x]; if(Mu.find(x)!=Mu.end())return Mu[x]; 9 int a=1;for(int i=2,N,l;N=x/i,i<=x;i=l)l=x/N+1,a-=(l-i)*MU(N);return a; 10 } 11 int qpow(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;} 12 long long C(int n,int k){ 13 long long a=1;if(n<k)return 0; 14 if(n<M)a=1ll*fac[n]*qpow(fac[n-k],mod-2)%mod; 15 else for(int i=n;i>n-k;--i)a=a*i%mod; 16 return a*iv[k]%mod; 17 } 18 main(){mu[1]=iv[1]=fac[1]=1,fac[0]=1;//freopen("1.in","r",stdin); 19 for(int i=2;i<M;++i){ 20 if(!np[i])mu[p[++pc]=i]=-1; 21 for(int j=1,x;j<=pc&&(x=p[j]*i)<M;++j) 22 if(i%p[j])mu[x]=-mu[i],np[x]=1; 23 else{np[x]=1;break;} 24 }for(int i=2;i<M;++i)mu[i]+=mu[i-1],fac[i]=1ll*fac[i-1]*i%mod; 25 for(int i=2;i<1001;++i)iv[i]=mod-mod/i*1ll*iv[mod%i]%mod; 26 for(int i=2;i<1001;++i)iv[i]=1ll*iv[i]*iv[i-1]%mod;//puts("in"); 27 int t;cin>>t;while(t--){ 28 int n,k,a=0;cin>>n>>k; 29 for(int i=1,l,N;N=n/i,i<=n;i=l+1)l=n/N,a=(a+(MU(l)-MU(i-1))*C(N+k-1,k))%mod; 30 cout<<(a+mod)%mod<<endl; 31 } 32 }
T2:B君的回忆
题目大意:$g(i)=g(i-1) imes 3 -g(i-2),g(0)=a,g(1)=b$求$g(g(g(g(...g(n)...)))) (mod p)$中$k$层嵌套。
$T le 1000,a,b,n,ple 10^9,kle 100$
可以说是结论题。没人会证明。
对于$k=1$矩阵快速幂就可以了。
对于$k=2$,内层的那个东西还是可以矩阵快速幂,但是。。。没有模数?项数貌似不可以直接取模。
发现每一项都由前两项递推,还是在模意义下的,不难想到它有循环节,但是我只知道循环节长度小于$n^2$。
结论来了,循环节长度为$O(n)$,$skyh$打表发现是$2n$及以下,所以其实不是很大。
找循环节能想到什么?显然$BSGS$啊。
然而对于原数列求循环节,不能单元素查找而要和前面的元素成对考虑,长度为$O(p)$还是很难弄。
所以我们考虑找矩阵的循环节,你只要找到两个相同的矩阵就行。
然后这题差不多就没了。然而这样可能会被卡常。
因为模数不保证是质数(尤其是递归下去以后就很可能不是质数了),所以考虑把模数质因数分解。
循环节长度自然是积性函数,然而实际上直接乘的确可能找到可行解但是却不一定最优,事实上取lcm即可。
还可以再优化,对于一种质因子$p^k$它的循环节是$p$的循环节乘$p^{k-1}$。结论。原理不明。
另外显而易见的找循环节可以记忆化。
这样你就可以AC了。代码很好写。
1 #include<bits/stdc++.h> 2 using namespace std; 3 unordered_map<int,int>Mr; 4 #define S 5689 5 int mod,rA,rB; 6 struct mtx{ 7 int b00,b01,b10,b11; 8 int hsh(){return (b00+b01*137ll+b10*15797ll+b11*1797193ll)%S;} 9 bool operator==(mtx y){return b00==y.b00&&b01==y.b01&&b10==y.b10&&b11==y.b11;} 10 void operator*=(mtx y){ 11 int _00=(1ll*b00*y.b00+1ll*b01*y.b10)%mod,_01=(1ll*b00*y.b01+1ll*b01*y.b11)%mod, 12 _10=(1ll*b10*y.b00+1ll*b11*y.b10)%mod,_11=(1ll*b11*y.b11+1ll*b10*y.b01)%mod; 13 b00=_00;b01=_01;b10=_10;b11=_11; 14 } 15 }bs,B,rbs,I; 16 struct Mtx{ 17 int a0,a1; 18 void operator*=(mtx y){ 19 int _0=(1ll*a0*y.b00+1ll*a1*y.b10)%mod,_1=(1ll*a0*y.b01+1ll*a1*y.b11)%mod; 20 a0=_0;a1=_1; 21 } 22 }ans,ra; 23 struct Hash_Map{ 24 #define Q 1055335 25 int fir[S],l[Q],c,v[Q];mtx m[Q]; 26 int&operator[](mtx x){ 27 int r=x.hsh(); 28 for(int i=fir[r];i;i=l[i])if(x==m[i])return v[i]; 29 l[++c]=fir[r];fir[r]=c;m[c]=x;return v[c]=0; 30 } 31 }M; 32 int Find(int p){ 33 M.c=0;for(int i=0;i<S;++i)M.fir[i]=0; 34 mod=p;int step=sqrt(p<<1)+1; 35 rbs=bs=(mtx){0,mod-1,1,3}; 36 bs=B;B=I; 37 for(int i=0;i<step;++i,B*=rbs)M[B]=i+1; 38 bs=B; 39 for(int i=1;i<step;++i,B*=bs)if(M[B])return i*step-M[B]+1; 40 } 41 int gcd(int x,int y){return y?gcd(y,x%y):x;} 42 int find(int mo){ 43 if(Mr[mo])return Mr[mo]; 44 long long mp=mo,ans=1,ta; 45 for(int i=2;i*i<=mp;++i)if(mp%i==0){ 46 mp/=i;ta=Find(i); 47 while(mp%i==0)mp/=i,ta*=i; 48 ans=ans*ta/gcd(ans,ta); 49 }if(mp^1)ta=Find(mp),ans=ans*ta/gcd(ans,ta); 50 return Mr[mo]=ans; 51 } 52 int g(int n,int k,int mo){//cerr<<n<<' '<<k<<' '<<mo<<endl; 53 if(k==1){ 54 mod=mo;bs=(mtx){0,mod-1,1,3};ans=(Mtx){rA,rB}; 55 for(;n;n>>=1,bs*=bs)if(n&1)ans*=bs; 56 return ans.a0; 57 }int x=g(n,k-1,find(mo)); 58 mod=mo;bs=(mtx){0,mod-1,1,3};ans=(Mtx){rA,rB}; 59 for(;x;x>>=1,bs*=bs)if(x&1)ans*=bs; 60 return ans.a0; 61 } 62 main(){I=(mtx){1,0,0,1};//freopen("17.in","r",stdin);freopen("my.out","w",stdout); 63 int t,n,k;cin>>t;while(t-->0)cin>>rA>>rB>>n>>k>>mod,cout<<g(n,k,mod)<<endl; 64 }
C:sanrd
题目大意:$f(x)=sumlimits_{i=0}^{n-1} A_i x^i$。对于每个$x=bc^{4k}+dc^{2k}+e$求值。$k$取遍$[0,n-1]$
$n le 60000,mod=1000003$。其余数据范围$le 10^6$
首先可以暴力。秦九韶展开就可以AC了。
其实就是减少取模次数,看代码就知道了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 unordered_map<int,int>Mr; 4 #define S 5689 5 int mod,rA,rB; 6 struct mtx{ 7 int b00,b01,b10,b11; 8 int hsh(){return (b00+b01*137ll+b10*15797ll+b11*1797193ll)%S;} 9 bool operator==(mtx y){return b00==y.b00&&b01==y.b01&&b10==y.b10&&b11==y.b11;} 10 void operator*=(mtx y){ 11 int _00=(1ll*b00*y.b00+1ll*b01*y.b10)%mod,_01=(1ll*b00*y.b01+1ll*b01*y.b11)%mod, 12 _10=(1ll*b10*y.b00+1ll*b11*y.b10)%mod,_11=(1ll*b11*y.b11+1ll*b10*y.b01)%mod; 13 b00=_00;b01=_01;b10=_10;b11=_11; 14 } 15 }bs,B,rbs,I; 16 struct Mtx{ 17 int a0,a1; 18 void operator*=(mtx y){ 19 int _0=(1ll*a0*y.b00+1ll*a1*y.b10)%mod,_1=(1ll*a0*y.b01+1ll*a1*y.b11)%mod; 20 a0=_0;a1=_1; 21 } 22 }ans,ra; 23 struct Hash_Map{ 24 #define Q 1055335 25 int fir[S],l[Q],c,v[Q];mtx m[Q]; 26 int&operator[](mtx x){ 27 int r=x.hsh(); 28 for(int i=fir[r];i;i=l[i])if(x==m[i])return v[i]; 29 l[++c]=fir[r];fir[r]=c;m[c]=x;return v[c]=0; 30 } 31 }M; 32 int Find(int p){ 33 M.c=0;for(int i=0;i<S;++i)M.fir[i]=0; 34 mod=p;int step=sqrt(p<<1)+1; 35 rbs=bs=(mtx){0,mod-1,1,3}; 36 bs=B;B=I; 37 for(int i=0;i<step;++i,B*=rbs)M[B]=i+1; 38 bs=B; 39 for(int i=1;i<step;++i,B*=bs)if(M[B])return i*step-M[B]+1; 40 } 41 int gcd(int x,int y){return y?gcd(y,x%y):x;} 42 int find(int mo){ 43 if(Mr[mo])return Mr[mo]; 44 long long mp=mo,ans=1,ta; 45 for(int i=2;i*i<=mp;++i)if(mp%i==0){ 46 mp/=i;ta=Find(i); 47 while(mp%i==0)mp/=i,ta*=i; 48 ans=ans*ta/gcd(ans,ta); 49 }if(mp^1)ta=Find(mp),ans=ans*ta/gcd(ans,ta); 50 return Mr[mo]=ans; 51 } 52 int g(int n,int k,int mo){//cerr<<n<<' '<<k<<' '<<mo<<endl; 53 if(k==1){ 54 mod=mo;bs=(mtx){0,mod-1,1,3};ans=(Mtx){rA,rB}; 55 for(;n;n>>=1,bs*=bs)if(n&1)ans*=bs; 56 return ans.a0; 57 }int x=g(n,k-1,find(mo)); 58 mod=mo;bs=(mtx){0,mod-1,1,3};ans=(Mtx){rA,rB}; 59 for(;x;x>>=1,bs*=bs)if(x&1)ans*=bs; 60 return ans.a0; 61 } 62 main(){I=(mtx){1,0,0,1};//freopen("17.in","r",stdin);freopen("my.out","w",stdout); 63 int t,n,k;cin>>t;while(t-->0)cin>>rA>>rB>>n>>k>>mod,cout<<g(n,k,mod)<<endl; 64 }
说实在的这题模数不好,所以我以为正解不是多项式。然而只是需要MTT。。。
然后这题也是个板子:多项式多点求值。前置是多项式除法,再前置是多项式求逆。
多点求值就是构造我们要求值的点生成一个多项式:$prod (x-x_i)$
分治。对于左边的那些点这个多项式的值为0,所以进行一次多项式取模,余数多项式就和A在右边的点值同余。
同时也学会了怎么做4次FFT实现MTT。利用虚部做乘法分配率,凑一凑就优化到了5次,然后利用复数性质可以优化到4次。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mod 1000003 4 #define S 131072 5 #define ll long long 6 #define lc p<<1 7 #define rc p<<1|1 8 const double pi=acos(-1); 9 struct cp{double r,i; 10 cp operator+(cp x){return (cp){r+x.r,i+x.i};} 11 cp operator-(cp x){return (cp){r-x.r,i-x.i};} 12 cp operator*(cp x){return (cp){r*x.r-i*x.i,r*x.i+i*x.r};} 13 void operator=(int x){r=x;i=0;} 14 }w[2][19][S],x,y,a[S],b[S],c[S],d[S]; 15 int rev[S],ib[S],pr[S],X[S],RA[S],RB[S];const int s=(1<<15)-1; 16 int pow(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;} 17 void FFT(cp*a,int n,int O){ 18 for(int i=1;i<n;++i)if(rev[i]>i)swap(a[i],a[rev[i]]); 19 for(int k=1,o=0;k<n;k<<=1,++o)for(int i=0;i<n;i+=k<<1)for(int j=i;j<i+k;++j) 20 x=a[j],y=a[j+k]*w[O][o][j-i],a[j]=x+y,a[j+k]=x-y; 21 if(!O)for(int i=0;i<n;++i)a[i].r/=n,a[i].i/=n; 22 } 23 ll r(double x){return (ll)(x+0.5)%mod;} 24 void MTT(int*A,int*B,int*C,int n){ 25 for(int i=0;i<n;++i)a[i].r=A[i]>>15,a[i].i=A[i]&s,b[i].r=B[i]>>15,b[i].i=B[i]&s,rev[i]=rev[i>>1]>>1|(i&1?n>>1:0); 26 FFT(a,n,1);FFT(b,n,1); 27 for(int i=0;i<n;++i)c[i]=b[i],c[i].i*=-1;reverse(c+1,c+n); 28 for(int i=0;i<n;++i)b[i]=b[i]*a[i],c[i]=c[i]*a[i]; 29 FFT(b,n,0);FFT(c,n,0); 30 for(int i=0;i<n;++i)C[i]=((r((b[i].r+c[i].r)*0.5)<<30)+(r(b[i].i)<<15)+r((c[i].r-b[i].r)*0.5))%mod; 31 } 32 void inv(int*a,int*b,int n){ 33 if(n==1){b[0]=pow(a[0],mod-2);return;} 34 inv(a,b,n+1>>1);int l=1;while(l<n<<1)l<<=1; 35 for(int i=0;i<l;++i)RA[i]=i<n?a[i]:0,RB[i]=i<n+1>>1?b[i]:0; 36 MTT(RA,RB,RA,l);MTT(RA,RB,RA,l); 37 for(int i=0;i<l;++i)b[i]=(RB[i]+RB[i]-RA[i]+mod)%mod; 38 } 39 void re(int*a,int n){for(int i=0;i<<1<n;++i)swap(a[i],a[n-1-i]);} 40 void MOD(int*a,int*b,int*r,int la,int lb){la++;lb++; 41 re(a,la);re(b,lb);inv(b,ib,la-lb+1); 42 int l=1;while(l<la<<1)l<<=1;MTT(a,ib,X,l); 43 for(int i=la-lb+1;i<l;++i)ib[i]=0; 44 re(X,la-lb+1);re(a,la);re(b,lb); 45 for(int i=la-lb+1;i<l;++i)X[i]=0; 46 MTT(X,b,pr,l); 47 for(int i=0;i<lb-1;++i)r[i]=(a[i]-pr[i]+mod)%mod; 48 } 49 int A[S],Q[S],_[S],__[S],___[S],len[S<<1];vector<int>V[S<<1]; 50 void build(int l,int r,int p){len[p]=r-l+1; 51 if(l==r){V[p].push_back(mod-Q[l]);V[p].push_back(1);len[p]=1;return;} 52 int md=l+r>>1,le=1;while(le<=r-l+1)le<<=1; 53 build(l,md,lc);build(md+1,r,rc); 54 for(int i=0;i<le;++i)_[i]=__[i]=___[i]=0; 55 for(int i=0;i<=len[lc];++i)_[i]=V[lc][i]; 56 for(int i=0;i<=len[rc];++i)__[i]=V[rc][i]; 57 MTT(_,__,___,le);for(int i=0;i<=r-l+1;++i)V[p].push_back(___[i]); 58 } 59 void solve(int l,int r,int*A,int p){ 60 if(r-l<625){ 61 for(int i=l,x;x=Q[i],i<=r;++i){ 62 long long ans=0,xp[26];int n=r-l+1;xp[0]=1; 63 for(int i=1;i<26;++i)xp[i]=1ll*xp[i-1]*x%mod; 64 for(int i=n/25*25;i>=0;i-=25){ 65 ans=ans%mod*xp[25]; 66 for(int j=0;j<25;++j)ans+=xp[j]*A[i+j]; 67 }printf("%lld ",ans%mod); 68 }return; 69 } 70 int md=l+r>>1,le=1;while(le<=len[p])le<<=1;int rp[le<<1],mb[le<<1]; 71 for(int i=0;i<le<<1;++i)rp[i]=mb[i]=0; 72 for(int i=0;i<=len[lc];++i)rp[i]=V[lc][i]; 73 MOD(A,rp,mb,len[p],len[lc]); 74 solve(l,md,mb,lc); 75 for(int i=0;i<le<<1;++i)rp[i]=mb[i]=0; 76 for(int i=0;i<=len[rc];++i)rp[i]=V[rc][i]; 77 MOD(A,rp,mb,len[p],len[rc]); 78 solve(md+1,r,mb,rc); 79 } 80 main(){ 81 register int n,b,c,d,e,r=1; 82 cin>>n>>b>>c>>d>>e;c=1ll*c*c%mod; 83 for(int i=0;1<<i<S;++i)for(int j=0;j<1<<i;++j) 84 w[0][i][j]=(cp){cos(pi/(1<<i)*j),sin(-pi/(1<<i)*j)}, 85 w[1][i][j]=(cp){cos(pi/(1<<i)*j),sin(+pi/(1<<i)*j)}; 86 for(int i=0;i<n;++i)scanf("%d",&A[i]); 87 for(register int i=0;i<n;++i)Q[i]=(1ll*b*r*r+1ll*d*r+e)%mod,r=1ll*r*c%mod; 88 build(0,n-1,1);solve(0,n-1,A,1); 89 }
上面这个做法太过无脑暴力?复杂度为$O(nlog^2n)$
正解复杂度要小一个$log$而且常数也小的多。
需要大力推式子,我大概看了看明白了意思但是没有时间写出来了。
然而NC不让粘他链接,而Dyyb粘了他的链接,于是我就粘Dyyb的链接好了,下次看的时候dfs一下就行。