日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CF838C-Future Failure【dp,子集卷积】

發布時間:2023/12/3 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CF838C-Future Failure【dp,子集卷积】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

正題

題目鏈接:https://www.luogu.com.cn/problem/CF838C


題目大意

一個字符串sss,兩個人輪流操作,每次每個人可以選擇刪掉一個字符或者重排列這個字符串,但是不能出現之前出現過的字符串,不能操作者輸。

求有多少個長度為nnn且字符集大小為kkk的字符串使得先手必勝。

1≤n≤250000,1≤k≤261\leq n\leq 250000,1\leq k\leq 261n250000,1k26


解題思路

顯然如果刪掉一個字符能使得先手必敗,那么先手必勝。如果不能,那么肯定會一直重排列這個字符串。

那么如果一個字符串的排列數是偶數,那么先手可以切換先后手,所以先手必勝。否則先手需要考慮能否刪除一個字符使得先手必敗。

設第iii個字符的數量是aia_iai?,那么一個字符串可重排列的方案就是n!∏i=1kai!\frac{n!}{\prod_{i=1}^ka_i!}i=1k?ai?!n!?,并且如果刪除一個字符iii,那么排列方式將會乘上ain\frac{a_i}{n}nai??

那么如果nnn是奇數,肯定存在一個aia_iai?是奇數,也就是說刪除一個iii后排列方式的奇偶性不變。所以如果一個nnn是奇數且字符串的排列數是奇數,那么肯定可以刪除一個字符使得排列數仍然是偶數。
那么如果nnn是奇數且先手,那么肯定不會被逼到一個走動后先手必勝的位置,所以nnn是奇數先手必勝。

然后如果nnn是偶數,那么如果排列方式是偶數那么先手必勝否則先手必敗。

然后考慮怎么計數nnn是偶數的情況。考慮到一個n!n!n!包含的222質因數的個數為∑i=0?n2i?\sum_{i=0}\lfloor\frac{n}{2^i}\rfloori=0??2in??,那么如果一個字符串的排列方式是偶數那么肯定有
∑i=0?n2i?=∑p=1k∑i=0?ap2i?\sum_{i=0}\left\lfloor\frac{n}{2^i}\right\rfloor=\sum_{p=1}^k\sum_{i=0}\left\lfloor\frac{a_p}{2^i}\right\rfloori=0??2in??=p=1k?i=0??2iap???
然后又因為假設我們考慮一直分解xxx出來,顯然∏i=1kai!\prod_{i=1}^ka_i!i=1k?ai?!xxx肯定不會比n!n!n!xxx多,同理分解2k2^k2k出來也是一樣的,所以它們每一個iii求出來的答案都是恰好相等的,即
?i∈N,?n2i?=∑p=1k?ap2i?\forall i\in N,\left\lfloor\frac{n}{2^i}\right\rfloor=\sum_{p=1}^k\left\lfloor\frac{a_p}{2^i}\right\rfloor?iN,?2in??=p=1k??2iap???
那么aia_iai?求和的時候二進制就不能有進位了,也就是說對于nnn中的每個111aia_iai?都恰好有一個是111nnn中的每一個000aia_iai?這一位都是000

也就是把nnn的二進制分成若干份aia_iai?,每一份的貢獻是1ai!\frac{1}{a_i!}ai?!1?,要求貢獻的乘積和。這個分出一個部分來的轉移其實就是子集卷積,所以我們跑kkk次子集卷積即可。

這樣跑有點慢,所以我們還需要快速冪優化。

時間復雜度:O(klog?knlog?2n)O(k\log kn\log ^2n)O(klogknlog2n)


code

#include<cstdio> #include<cstring> #include<algorithm> #define lowbit(x) (x&-x) using namespace std; const int N=1<<19; int n,k,P,f[20][N],g[20][N],c[N],inv[N],fac[N]; void FWT(int *f,int n,int op){for(int p=2;p<=n;p<<=1)for(int k=0,len=p>>1;k<n;k+=p)for(int i=k;i<k+len;i++)(f[i+len]+=f[i]*op)%=P;return; } signed main() {scanf("%d%d%d",&n,&k,&P);int ans=1;for(int i=1;i<=n;i++)ans=1ll*ans*k%P;fac[0]=inv[0]=inv[1]=1;for(int i=2;i<N;i++)inv[i]=P-1ll*inv[P%i]*(P/i)%P;for(int i=1;i<N;i++)fac[i]=1ll*fac[i-1]*i%P,inv[i]=1ll*inv[i-1]*inv[i]%P;if(n&1)return printf("%d\n",ans)&0;f[0][0]=1;int m=1,lg=0;while(m<=n)m<<=1,lg++;for(int i=1;i<m;i++)c[i]=c[i-lowbit(i)]+1;for(int i=0;i<=n;i++)g[c[i]][i]=inv[i];for(int i=0;i<c[n];i++)FWT(g[i],m,1);FWT(f[0],m,1);while(k){if(k&1){for(int i=c[n];i>=0;i--){for(int x=0;x<m;x++)f[i][x]=1ll*f[i][x]*g[0][x]%P;for(int j=1;j<=i;j++)for(int x=0;x<m;x++)f[i][x]=(f[i][x]+1ll*f[i-j][x]*g[j][x])%P;}}for(int i=c[n];i>=0;i--){for(int x=0;x<m;x++)g[i][x]=(i?2ll:1ll)*g[0][x]*g[i][x]%P;for(int j=1;j<i;j++)for(int x=0;x<m;x++)g[i][x]=(g[i][x]+1ll*g[j][x]*g[i-j][x])%P;}k>>=1;}FWT(f[c[n]],m,-1);ans=(ans-1ll*f[c[n]][n]*fac[n]%P)%P;printf("%d\n",(ans+P)%P);return 0; }

總結

以上是生活随笔為你收集整理的CF838C-Future Failure【dp,子集卷积】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。