[考试反思]数学专题测试2:重铸

这回真的是大众分了。肯定是不行的。。。联赛分已经比别人低了靠大众分不可能翻盘。

还指望着省选翻盘的话,肯定不能止步于此。

但是的确还是没有把能打的打满,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 }
View Code

T2:B君的回忆

题目大意:$g(i)=g(i-1) \times 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,p\le 10^9,k\le 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 }
View Code

C:sanrd

题目大意:$f(x)=\sum\limits_{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 }
然而暴力还是不应该AC的必须特判啊

说实在的这题模数不好,所以我以为正解不是多项式。然而只是需要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\n",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一下就行。

猜你喜欢

转载自www.cnblogs.com/hzoi-DeepinC/p/12153015.html