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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

AtCoder AGC019E Shuffle and Swap (DP、FFT、多项式求逆、多项式快速幂)

發布時間:2025/3/15 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 AtCoder AGC019E Shuffle and Swap (DP、FFT、多项式求逆、多项式快速幂) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接

https://atcoder.jp/contests/agc019/tasks/agc019_e

題解

tourist的神仙E題啊做不來做不來……這題我好像想歪了啊= =……

首先我們可以考慮,什么樣的操作序列才是合法的?
有用的位置只有兩種,一種是兩個序列在這個位置上都是1, 稱作11型,另一種是一個0一個1, 稱作01型。設兩種位置分別有\(A\)個和\(2B\)個。
考慮一個操作序列,交換兩個11型相當于沒交換,每個11型只會被交換兩次,每個01型只會被交換一次。這也就是說,如果我們從shuffle之后的\(a_i\)\(b_i\)連邊,那么形成的圖一定是若干個環加上\(m\)條鏈,鏈的開頭結尾都是01型,中間是11型。對于鏈來說,上面操作的順序必須固定;對于環來說,上面操作的順序可以任意。

下面有兩種處理方式。

做法一

\(dp[i][j]\)表示把\(i\)個無標號的11型放到\(j\)條鏈中,可得DP式: \(dp[i][j]=\sum_{k\le 0}\frac{dp[i-1][j-k]}{(k+1)!}\), 其中分母的含義是鏈上\((u+1)\)個點順序固定,最后的答案是\(A!B!(A+B)!\sum^A_{i=0}dp[B][i]\). \((A+B)!\)表示將邊隨意排序,\(A!B!\)表示11型和01型點之間是有標號的。
時間復雜度\(O(n^3)\).

但是我們發現這個DP就相當于在給多項式\(\sum_{n\le 0}\frac{1}{(n+1)!}x^n\)進行冪運算,于是用多項式快速冪加速即可,時間復雜度\(O(n\log^2n)\)\(O(n)\).

做法二

有沒有聰明一點的做法?有!
\(dp[i][j]\)表示目前一共放了\(i\)個11型和\(j\)個01型鏈(考慮已經放了的元素的標號,但是每次僅僅是往右添加),我們強行轉移!
\(dp[i][j]=j^2\times dp[i][j-1]+ij\times dp[i-1][j]\)
前一個式子是要加一個新的01型鏈,選兩個01型;后一個式子是要選一個鏈,再把這條鏈的結尾端點任意擴展一個位置。
答案就是\(\sum_{k}{A\choose k}\times f[k][B]\times ((A-k)!)^2\times {A+B\choose A-k}\), 其中\(A+B\choose A-k\)是選出位置,\(A\choose k\)是選出編號,\(((A-k)!)^2\)是求出組成環的方案數。
時間復雜度\(O(n^2)\), 可以通過。

但是我們發現這個DP還可以用多項式優化!
\(g[i][j]=\frac{dp[i][j]}{(j!)^2i!}\), 顯然有\(g[i][j]=g[i][j-1]+j\times g[i-1][j]\)
然后這個使用NE Lattice Path的方式來理解,就是從\((0,0)\)走到\((i,j)\),每往上走一次路徑權值乘上橫坐標,求所有路徑權值和。
考慮另一種DP,枚舉在第\(i\)行走幾步,那么發現第\(i\)列的生成函數就是\(\frac{1}{1-ix}\), 然后答案就是所有列生成函數之積
于是可以分治NTT+多項式求逆計算,時間復雜度\(O(n\log^2n)\).

代碼

做法二\(O(n^2)\)

#include<cstdio> #include<cstdlib> #include<iostream> #include<cassert> #include<cstring> #define llong long long using namespace std;const int N = 2e4; const int P = 998244353; const llong INV2 = 499122177; llong fact[N+3],finv[N+3];llong quickpow(llong x,llong y) {llong cur = x,ret = 1ll;for(int i=0; y; i++){if(y&(1ll<<i)) {y-=(1ll<<i); ret = ret*cur%P;}cur = cur*cur%P;}return ret; } llong mulinv(llong x) {return quickpow(x,P-2);} llong comb(llong x,llong y) {return x<0||y<0||x<y ? 0ll : fact[x]*finv[y]%P*finv[x-y]%P;}int n,a,b; char s[N+3],t[N+3]; llong dp[2][N+3];int main() {fact[0] = 1ll; for(int i=1; i<=N; i++) fact[i] = fact[i-1]*i%P;finv[N] = quickpow(fact[N],P-2); for(int i=N-1; i>=0; i--) finv[i] = finv[i+1]*(i+1)%P;scanf("%s%s",s+1,t+1); n = strlen(s+1);for(int i=1; i<=n; i++){if(s[i]=='1' && t[i]=='1') {a++;}else if(s[i]^t[i]) {b++;}}b>>=1;int cur = 0,prv = 1;dp[0][0] = 1ll;for(int j=1; j<=b; j++){cur^=1; prv^=1;dp[cur][0] = dp[prv][0]*j*j%P;for(int i=1; i<=a; i++){dp[cur][i] = (dp[prv][i]*j*j+dp[cur][i-1]*i*j)%P; // printf("dp[%d][%d]=%lld\n",i,j,dp[cur][i]);}}llong ans = 0ll;for(int k=0; k<=a; k++){ans = (ans+dp[cur][k]*comb(a,k)%P*fact[a-k]%P*fact[a-k]%P*comb(a+b,a-k))%P; // printf("k%d ans%lld\n",k,ans);}printf("%lld\n",ans);return 0; }

總結

以上是生活随笔為你收集整理的AtCoder AGC019E Shuffle and Swap (DP、FFT、多项式求逆、多项式快速幂)的全部內容,希望文章能夠幫你解決所遇到的問題。

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