沒得說。怎么這么菜啊。
$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 }