AtCoder 4169 [ARC100D] Colorful Sequences(dp)
problem
洛谷鏈接
solution
逆向考慮。ans=ans=ans= 所有蛋糕中的 aaa 序列出現(xiàn)次數(shù) ?-? 在 non?colorfulnon-colorfulnon?colorful 蛋糕中的出現(xiàn)次數(shù)。
在所有蛋糕中的出現(xiàn)次數(shù),即 (n?m+1)?kn?m(n-m+1)·k^{n-m}(n?m+1)?kn?m,枚舉 aaa 序列開頭的位置,除去 aaa 序列占據(jù)的位置以外的位置的顏色是隨便的 1~k1\sim k1~k。
因為 aaa 的出現(xiàn)是可以有重復(fù)位置的,所以每個位置的序列的貢獻都是獨立計算的,沒有什么需要去重的問題。
然后考慮在 non?colorfulnon-colorfulnon?colorful 蛋糕中的出現(xiàn)次數(shù)。
-
首先得特判,aaa 本身就已經(jīng)是一個 colorfulcolorfulcolorful 蛋糕。那么只要包含 aaa 就一定是滿足條件的蛋糕。
直接輸出在所有蛋糕中的出現(xiàn)次數(shù)結(jié)束程序。
-
aaa 蛋糕顏色序列中各個顏色互不相同。
考慮用 dpdpdp 來做。
設(shè) f(i,j):f(i,j):f(i,j): 到 iii 為止,后面一段連續(xù)顏色各不相同的長度為 jjj,即 [i?j+1,i][i-j+1,i][i?j+1,i] 顏色互不相同,的 non?colorfulnon-colorfulnon?colorful 蛋糕個數(shù)。
設(shè)計 i?1→ii-1\rightarrow ii?1→i 的轉(zhuǎn)移方程。
-
隨便新選一個未曾出現(xiàn)的顏色。
f(i?1,j?1)?(k?j+1)→f(i,j):f(i-1,j-1)·(k-j+1)\rightarrow f(i,j):f(i?1,j?1)?(k?j+1)→f(i,j):。
-
i?1i-1i?1 的長度更長,在 iii 時選擇了和恰當(dāng)位置相同顏色,將 i?1i-1i?1 恰好卡成了 jjj 的長度。
f(i?1,j′)→f(i,j)j′≥jf(i-1,j')\rightarrow f(i,j)\quad j'\ge jf(i?1,j′)→f(i,j)j′≥j。
設(shè) gi,j:g_{i,j}:gi,j?: 記錄 fi,jf_{i,j}fi,j? 類的所有可能蛋糕中出現(xiàn) a1,...,ma_{1,...,m}a1,...,m? 的個數(shù)。
事實上,我們轉(zhuǎn)移時并不知道具體的蛋糕長相,所以不能判斷是否連續(xù)長度為 mmm 的未重復(fù)的就一定是 aaa。
所以在轉(zhuǎn)移時只要 j≥mj\ge mj≥m,即出現(xiàn)連續(xù)長度達到 mmm 的互不相同顏色的連續(xù)蛋糕層,就記錄貢獻。
f(i,j)→g(i,j)f(i,j)\rightarrow g(i,j)f(i,j)→g(i,j)。
因為連續(xù)長度有 mmm 的連續(xù)蛋糕層的每種情況都是均勻分布,最后限制其順序和顏色值,即 /A(k,m)/A(k,m)/A(k,m) 即可。
-
-
aaa 蛋糕顏色序列中有重復(fù)顏色。
也就是說,判斷一個蛋糕是否是 colorfulcolorfulcolorful 的區(qū)間一定不會橫跨 / 完全包含 aaa。
那么 aaa 就將整個蛋糕劃分成了前一部分,aaa ,后一部分,三部分彼此獨立。
枚舉 aaa 的開始位置,可以使用卷積 / 乘法定理求左右蛋糕組合情況,分開求解,進而是一整個蛋糕的顏色序列可能數(shù)。
顯然,求解計算的 non?colorfulnon-colorfulnon?colorful 個數(shù)與上面 fff 是一樣的轉(zhuǎn)移。
只是在初始化上有所不同。
對 aaa 求前綴和后綴最長不重復(fù)顏色長度,分別記為 l,rl,rl,r。
用 f(i,j)f(i,j)f(i,j) 來計算前一部分,g(i,j)g(i,j)g(i,j) 來計算后一部分,這里的 f,gf,gf,g 與上一種情況的 f,gf,gf,g 并不一樣。
f0,0=f0,1=...=f0,l=g0,0=g0,1=...=g0,r=1f_{0,0}=f_{0,1}=...=f_{0,l}=g_{0,0}=g_{0,1}=...=g_{0,r}=1f0,0?=f0,1?=...=f0,l?=g0,0?=g0,1?=...=g0,r?=1。
-
注意:這里算的是 non?colorfulnon-colorfulnon?colorful 蛋糕中的貢獻,所以在 dpdpdp 中不能讓連續(xù)未重復(fù)顏色長度達到 kkk。
code
#include <bits/stdc++.h> using namespace std; #define mod 1000000007 #define int long long #define maxn 25005 #define maxk 405 int n, k, m; int a[maxn]; int f[maxn][maxk], g[maxn][maxk]; bool vis[maxk];int qkpow( int x, int y ) {int ans = 1;while( y ) {if( y & 1 ) ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans; }bool check( int l, int r ) {memset( vis, 0, sizeof( vis ) );for( int i = l;i <= r;i ++ )if( vis[a[i]] ) return 0;else vis[a[i]] = 1;return 1; }bool colorful() { //判斷a是否本身就是彩虹的for( int i = 1;i + k - 1 <= m;i ++ )if( check( i, i + k - 1 ) ) return 1;return 0; }signed main() {scanf( "%lld %lld %lld", &n, &k, &m );for( int i = 1;i <= m;i ++ ) scanf( "%lld", &a[i] );int ans = ( n - m + 1 ) * qkpow( k, n - m ) % mod;if( colorful() ) return ! printf( "%lld\n", ans );int l = -1, r = -1;memset( vis, 0, sizeof( vis ) );for( int i = 1;i <= m;i ++ )if( vis[a[i]] ) { l = i - 1; break; }else vis[a[i]] = 1;memset( vis, 0, sizeof( vis ) );for( int i = m;i >= 1;i -- )if( vis[a[i]] ) { r = m - i; break; }else vis[a[i]] = 1;int tot;if( ! ~l ) {f[0][0] = 1;for( int i = 1;i <= n;i ++ ) {for( int j = 1;j < k;j ++ ) {/*因為不能是colorful所以不能讓未重復(fù)長度達到k1.f[i-1][j-1]->f[i][j] 隨便加一個未出現(xiàn)的數(shù)字 有(k-j+1)種因為f'[i-1]是后綴和過的 f'[i-1][j-1]-f'[i-1][j]=f[i-1][j-1]2.f[i-1][j<=j']->f[i][j] 選擇合適位置對應(yīng)的數(shù)字 將未重復(fù)長度減小因為f'[i-1]是后綴和過的 f[i-1][j<=j']=f[i][j]*/f[i][j] = ((f[i - 1][j - 1] - f[i - 1][j] + mod) % mod * (k - j + 1) % mod + f[i - 1][j]) % mod;g[i][j] = ((g[i - 1][j - 1] - g[i - 1][j] + mod) % mod * (k - j + 1) % mod + g[i - 1][j]) % mod;if( j >= m ) ( g[i][j] += f[i][j] ) %= mod; //當(dāng)長度達到m的時候就可以計算個數(shù)了}for( int j = k - 1;j;j -- ) { //后綴和( f[i][j - 1] += f[i][j] ) %= mod;( g[i][j - 1] += g[i][j] ) %= mod;}}tot = g[n][0]; //此時的g只是算的長度為m的未重復(fù)的個數(shù) 包含了給出的a 還有一些其余的數(shù)列//這里的a強調(diào)順序以及數(shù)值 所以要除以A(k,m)for( int i = k;i > k - m;i -- ) tot = tot * qkpow( i, mod - 2 ) % mod;}else {//前后卷積for( int i = 0;i <= l;i ++ ) f[0][i] = 1;for( int i = 0;i <= r;i ++ ) g[0][i] = 1;for( int i = 1;i <= n;i ++ ) {for( int j = 1;j < k;j ++ ) {f[i][j] = ((f[i - 1][j - 1] - f[i - 1][j] + mod) % mod * (k - j + 1) % mod + f[i - 1][j]) % mod;g[i][j] = ((g[i - 1][j - 1] - g[i - 1][j] + mod) % mod * (k - j + 1) % mod + g[i - 1][j]) % mod;}for( int j = k - 1;j;j -- ) {( f[i][j - 1] += f[i][j] ) %= mod;( g[i][j - 1] += g[i][j] ) %= mod;}}tot = 0;for( int i = 0;i <= n - m;i ++ )tot = ( tot + f[i][0] * g[n - m - i][0] % mod ) % mod;}printf( "%lld\n", ( ans - tot + mod ) % mod );return 0; }總結(jié)
以上是生活随笔為你收集整理的AtCoder 4169 [ARC100D] Colorful Sequences(dp)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 记github学生认证
- 下一篇: 杨万里