[考试反思]0520省选模拟101:目的
没得说。怎么这么菜啊。
$T1$的$60$分白送的基本都不用想。
(诶那我这场考试干啥了?
$T2$看着像个$min25$筛的板子。就是数据范围大了点
然而因为几乎没怎么遇到过$min25$的题,只写过一次而且还是三个月前了。
所以基本上是忘的一干二净考场上一点一点尝试想的。
结果写的混天黑地终于写完,过掉样例,就交了。
十分快乐的是:少取了个模。直接爆零。然后这场就没了。
就当是练习不熟练的知识点了(自己都不信。。。
我到现在都不知道我这么做的目的是什么。但愿不要再考场弱智了(事实上明天还是这样
T1:石子游戏
大意:$nim$。问去掉最少几堆石子后可以先手必胜。$n \le 5 \times 10^5,A \le 5 \times 10^5$
要求出最少用多少个堆能得到和所有石子堆一样的异或值。
删掉的石子堆数是$logA$级别。否则线性基可以表出就可以去掉了。
所以暴力做$dp$是$O(n^2)$的。每一轮用$xorFWT$优化可以做到$O(nlog^2n)$。用$FWT$本质求单点点值可以做到$O(nlogn)$
1 #include<cstdio> 2 #define S 1<<19 3 int a[S],n,t[S],T,ans; 4 void FWT(int*a){for(int i=1;i<S;i<<=1)for(int j=0;j<S;j+=i<<1)for(int k=j,x,y;k<j+i;++k)x=a[k],y=a[k+i],a[k]=x+y,a[k+i]=x-y;} 5 int main(){ 6 scanf("%d",&n);n++; 7 for(int i=1,x;i<n;++i)scanf("%d",&x),T^=x,t[x]=1; 8 a[T]=1; FWT(t); 9 while(n--,!a[0]){FWT(a);for(int i=0;i<S;++i)a[i]=a[i]*t[i];FWT(a);for(int i=0;i<S;++i)a[i]=a[i]?1:0;} 10 printf("%d\n",n); 11 }
T2:函数
大意:$f(p^e)=p^k,f(ab)=f(a)f(b)((a,b)=1)$。求$\sum\limits_{i=1}^{n} f(i)$。$n \le 10^{13},k \le 20$
送上$min25$模板。
1 #include<cstdio> 2 #include<cmath> 3 #define ll long long 4 #define mod 1000000007 5 const int S=12345678,s=3333333; 6 ll n,v[S];int k,iv[23],st[23][23],g0[s],g1[s],p[S],pc,vc,sq,f[s],pre[s]; bool np[S]; 7 int&g(ll x){return x<=sq?g0[x]:g1[n/x];} 8 int mo(int x){return x>=mod?x-mod:x;} 9 int spw(ll n,int k,int a=0){n%=mod;for(int i=0,C=n+1;i<=k;++i)a=(a+1ll*st[k][i]*C%mod*iv[i+1])%mod,C=C*1ll*(n-i)%mod;return a;} 10 int pw(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;} 11 int Sum(ll n,int c,int a=0){ 12 if(p[c]>n||n<=1)return 0; 13 for(int z=c;z<=pc&&1ll*p[z]*p[z]<=n;++z) 14 for(ll t=p[z];1ll*t*p[z]<=n;t*=p[z])a=(a+f[p[z]]*(1ll+Sum(n/t,z+1)))%mod; 15 return mo(a+mo(g(n)-pre[c-1]+mod)); 16 } 17 int main(){ 18 scanf("%lld%d",&n,&k); 19 st[0][0]=iv[1]=1; sq=sqrt(n); 20 for(int i=1;i<=k;++i)for(int j=1;j<=i;++j)st[i][j]=(st[i-1][j]*1ll*j+st[i-1][j-1])%mod; 21 for(int i=2;i<23;++i)iv[i]=mod-mod/i*1ll*iv[mod%i]%mod; 22 23 f[1]=pre[0]=1; 24 for(int i=2;i<=sq;++i){ 25 if(!np[i])p[++pc]=i,f[i]=pw(i,k),pre[pc]=mo(pre[pc-1]+f[i]); 26 for(int j=1,x;(x=i*p[j])<=sq;++j){ 27 np[x]=1; f[x]=f[i]*f[p[j]]; 28 if(i%p[j]==0){f[x]=f[i];break;} 29 } 30 } 31 for(ll i=1,r,N;N=n/i,i<=n;i=r+1)r=n/N,v[++vc]=N; 32 for(int i=1;i<=vc;++i)g(v[i])=spw(v[i],k)-(!k); 33 for(int i=1;i<=pc;++i)for(int j=1;1ll*p[i]*p[i]<=v[j];++j)g(v[j])=(g(v[j])-1ll*(g(v[j]/p[i])-pre[i-1])*f[p[i]]%mod+mod)%mod; 34 printf("%d\n",mo(Sum(n,1)+1+mod)); 35 }
我们构造一个$g(x)=x^k$。再尝试设计一个$h$使得$f=g*h$。是狄利克雷卷积。
$f(1)=g(1)h(1)$。所以有$h(1)=1$
$f(p)=g(p)h(1)+h(p)g(1)$。所以有$h(p)=0$
继续搞下去,还有$h(p^e)=p^e-p^{2e}$。当然$h$也是积性函数。
那么我们就知道$h$只在$powerful\ number$处有值。
设$G(n)=\sum\limits_{i=1}^{n} g(i)$。是个自然数幂和可以$O(k)$算
$\sum\limits_{i=1}^{n} f(i) =\sum\limits_{j=1}^{n} \sum\limits_{d|i}g(d)h(\frac{n}{i})$
$=\sum\limits_{i=1}^{n} h(i) \sum\limits_{j=1}^{\frac{n}{i}} j$
$=\sum\limits_{i=1}^{n} h(i) G(\frac{n}{i})$
爆搜出所有的$powerful \ number$(每次搜索必定找到一个,总共的数量是$\sqrt{n}$级别)。对于每个$powerful \ number$计算一个对应的$G$也就是自然数幂和
复杂度$O(k\sqrt{n})$。可能有点卡常,自然数幂和可以记忆化。
1 #include<cstdio> 2 #include<cmath> 3 #define ll long long 4 const int S=10000007,mod=1000000007; 5 ll n;int k,iv[23],st[23][23],p[S],pc,sq,h[S]; bool np[S]; 6 int spw(int n,int a=0){for(int i=0,C=n+1;i<=k;++i)a=(a+1ll*st[k][i]*C%mod*iv[i+1])%mod,C=C*1ll*(n-i)%mod;return a;} 7 int pw(int b,int t=k,int a=1){for(;t;t>>=1,b=1ll*b*b%mod)if(t&1)a=1ll*a*b%mod;return a;} 8 struct hash_map{ 9 int fir[S],l[S],v[S],ec;ll to[S]; 10 int&operator[](ll x){int r=x%S; 11 for(int i=fir[r];i;i=l[i])if(to[i]==x)return v[i]; 12 l[++ec]=fir[r];fir[r]=ec;to[ec]=x;return v[ec]=spw(x%mod); 13 } 14 }M; 15 int Sum(ll n,int hp,int c,int a=0){ 16 for(int z=c;z<=pc;++z){ 17 ll t=n/p[z]/p[z]; if(!t)break; int Hp=hp*1ll*h[p[z]]%mod; 18 for(;t;t/=p[z])a=(a+Sum(t,Hp,z+1))%mod; 19 }return (a+1ll*hp*M[n])%mod; 20 } 21 int main(){ 22 scanf("%lld%d",&n,&k); 23 st[0][0]=iv[1]=1; sq=sqrt(n); 24 for(int i=1;i<=k;++i)for(int j=1;j<=i;++j)st[i][j]=(st[i-1][j]*1ll*j+st[i-1][j-1])%mod; 25 for(int i=2;i<23;++i)iv[i]=mod-mod/i*1ll*iv[mod%i]%mod; 26 for(int i=2;i<=sq;++i){ 27 if(!np[i])p[++pc]=i,h[i]=pw(i)-pw(1ll*i*i%mod),h[i]+=h[i]<0?mod:0; 28 for(int j=1,x;(x=i*p[j])<=sq;++j){np[x]=1;if(i%p[j]==0)break;} 29 }printf("%d",Sum(n,1,1)); 30 }
T3:画
大意:图,每个点$i$的权值在$[0,limit_i]$。有边相邻的两个点权值不同。所有点异或和为给定值$C$。$n \le 15,limit,C \le 10^{18}$
先考虑没有边。那感觉上就是一个数位$dp$了。
我们逐位考虑,并且强制目前考虑位的更高位上所有数都紧贴上界(如果贴到上界和$C$的高位不符则直接跳出)
设$dp[i][0/1][0/1]$表示考虑了前$i$个数,是否有数脱离上界,当前考虑位上是$1$还是$0$。
这个可以简单转移。$dp[n][1][bit(C,x)]$就是答案。复杂度是$O(n\times logC)$
然后考虑边数很少的情况。不难想到容斥,状压枚举那些边符合条件。子集反演得到容斥系数就是$-1$的边集的大小次幂。
考虑优化,在刚才这种想法里有一些冗余状态,例如说$1-2,2-3$相同而$1-3$不同。这显然是非法的。
所以我们枚举一个点集,点集的系数是:在当前点集所有联通导出子图的容斥系数之和。
也就是每次强制一个点集同色,不同点集不限制来进行计算。
这个系数可以用全集减非法得到。每次枚举$1$号点所在连通块。由于正负组合数和为$0$,所以可以知道所有存在边的子集的所有导出子图(不一定联通)的容斥系数和为$0$否则为$1$。
这样就很好转移了。设$dp[i][j]$表示当前已选点集是$i$,全局所有点的异或和相当于$j$集合所有点的异或和。
考虑怎么得到$j$:如果一个连通块大小是偶数,那么为全局异或和贡献是$0$。如果是奇数,那么取决于$limit$最小的点。
我们知道$j$一定是$i$的子集。状态数是$n^3$的。转移时钦定最小点必须被包含,枚举补集的子集。
因为有对于当前点集$j$中$limit$最大的点,它右侧一定不存在$2$。这样是$\sum 3^i 2^{n-i}$。积分出来还是$3^n$。所以复杂度是对的。
1 #include<cstdio> 2 #include<algorithm> 3 #define ll long long 4 #define mod 998244353 5 #define S 1<<15 6 int n,m,ie[S],ans,c[S],bit[S],pw[S],t23[S],dp[55555555],mnp[S]; ll a[16],C; 7 void mo(int&x){if(x>=mod)x-=mod;} 8 int&T(int s,int t){return dp[t23[s]+t23[t]];} 9 #define any (1ll<<i) 10 #define lim ((a[j]&any-1)+1) 11 int ask(int s,int A=0){ 12 static int dp[16][2][2];dp[0][0][0]=1; 13 for(int i=59,c;c=0,~i;--i){ 14 for(int j=1;j<=n;++j){ 15 if(s>>j-1&1^1){for(int x=0;x<2;++x)for(int y=0;y<2;++y)dp[j][x][y]=dp[j-1][x][y];continue;} 16 dp[j][0][0]=dp[j][0][1]=dp[j][1][0]=dp[j][1][1]=0; 17 for(int x=0;x<2;++x)for(int y=0;y<2;++y) 18 if(a[j]>>i&1)mo(dp[j][1][y]+=dp[j-1][x][y]*(x?any%mod:1)%mod),mo(dp[j][x][y^1]+=dp[j-1][x][y]*(lim%mod)%mod); 19 else mo(dp[j][x][y]+=dp[j-1][x][y]*(lim%mod)%mod); 20 c^=a[j]>>i&1; 21 }mo(A+=dp[n][1][C>>i&1]); if(C>>i&1^c)break;else A+=!i; 22 }return A; 23 } 24 int main(){ 25 scanf("%d%d%lld",&n,&m,&C); a[0]=2e18; 26 for(int i=1;i<=n;++i)scanf("%lld",&a[i]),mnp[1<<i-1]=i; 27 for(int i=1,x,y;i<=m;++i){ 28 scanf("%d%d",&x,&y); 29 for(int j=0;j<1<<n;++j)if(j&1<<x-1&&j&1<<y-1)ie[j]=1; 30 } 31 for(int i=1;i<1<<n;++i)bit[i]=bit[i^i&-i]^1,mnp[i]=i^i&-i?(mnp[i&-i^(a[mnp[i^i&-i]]<a[mnp[i&-i]]?i:0)]):mnp[i]; 32 for(int i=pw[0]=1;i<n;++i)pw[i]=pw[i-1]*3; 33 for(int i=0;i<1<<n;++i)for(int j=0;j<n;++j)if(i>>j&1)t23[i]+=pw[j]; 34 for(int i=1;i<1<<n;++i){ 35 int x=i&-i;c[i]=!ie[i]; 36 for(int j=i-1&i;j;j=j-1&i)if(j&x&&!ie[i^j])mo(c[i]+=mod-c[j]); 37 } 38 dp[0]=1; int U=(1<<n)-1; 39 for(int i=0;i<=U;++i)for(int j=i,l=!j;l<2;j=j-1&i,l+=l+!j)if(T(i,j))for(int e=U^i,r=e;r;r=r-1&e)if((e&-e)==(r&-r)) 40 if(bit[r])mo(T(i|r,j|1<<mnp[r]-1)+=1ll*T(i,j)*c[r]%mod); 41 else mo(T(i|r,j)+=1ll*T(i,j)*c[r]%mod*((a[mnp[r]]+1)%mod)%mod); 42 for(int i=0;i<1<<n;++i)if(T(U,i))mo(ans+=1ll*ask(i)*T(U,i)%mod); 43 printf("%d",ans); 44 }