[考试反思]0520省选模拟101:目的

没得说。怎么这么菜啊。

$T1$的$60$分白送的基本都不用想。

(诶那我这场考试干啥了?

$T2$看着像个$min25$筛的板子。就是数据范围大了点

然而因为几乎没怎么遇到过$min25$的题,只写过一次而且还是三个月前了。

所以基本上是忘的一干二净考场上一点一点尝试想的。

结果写的混天黑地终于写完,过掉样例,就交了。

十分快乐的是:少取了个模。直接爆零。然后这场就没了。

就当是练习不熟练的知识点了(自己都不信。。。

我到现在都不知道我这么做的目的是什么。但愿不要再考场弱智了(事实上明天还是这样

T1:石子游戏

大意:$nim$。问去掉最少几堆石子后可以先手必胜。$n le 5 imes 10^5,A le 5 imes 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);
11 }
View Code

T2:函数

大意:$f(p^e)=p^k,f(ab)=f(a)f(b)((a,b)=1)$。求$sumlimits_{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
",mo(Sum(n,1)+1+mod));
35 }
View Code

我们构造一个$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)=sumlimits_{i=1}^{n} g(i)$。是个自然数幂和可以$O(k)$算

$sumlimits_{i=1}^{n} f(i) =sumlimits_{j=1}^{n} sumlimits_{d|i}g(d)h(frac{n}{i})$

$=sumlimits_{i=1}^{n} h(i) sumlimits_{j=1}^{frac{n}{i}} j$

$=sumlimits_{i=1}^{n} h(i) G(frac{n}{i})$

爆搜出所有的$powerful number$(每次搜索必定找到一个,总共的数量是$sqrt{n}$级别)。对于每个$powerful number$计算一个对应的$G$也就是自然数幂和

复杂度$O(ksqrt{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 }
View Code

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 imes 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 }
View Code
原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12934133.html