1. 程式人生 > >CF - 1111D Destroy the Colony DP

CF - 1111D Destroy the Colony DP

for n) 代碼 amp fine push esp gif second

題目傳送門

題意:

這個題目真的是最近遇到的最難讀。

有一個長度n的字符串,每一位字符都代表的是該種種類的敵人。

現在如果一個序列合法的話,就是同一種種類的敵人都在字符串的左半邊或者右半邊。

現在有q次詢問,現在問你將 s[x] 和 s[y] 的敵人都放在同一邊的合法方案數是多少。

題解:

首先如果劃分組之後,那麽答案就是,m! * m! * 2/ (c1! * c2! * c3! .... )

然後對於每一組來說就是 這個值是一定的。

然後就是需要求這個分組方案數。

對於分組方案數,可以通過背包來求這個方案數是多少。

但是如果枚舉每個同類的字符,那麽最後的復雜度是52 * 52 * 52 * n。

所以可以將總方案數先算出來,然後再將x,y的方案數,從裏面刪除,刪除之後,不含x,y的方案數,相當於含了x,y的方案數。 這個復雜度是52*52*n。

代碼:

技術分享圖片
/*
code by: zstu wxk
time: 2019/02/07
*/
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define
se second #define pb push_back #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] #define max3(a,b,c) max(a,max(b,c)) #define min3(a,b,c) min(a,min(b,c)) typedef pair<int,int> pll; const int inf = 0x3f3f3f3f; const int _inf = 0xc0c0c0c0
; const LL INF = 0x3f3f3f3f3f3f3f3f; const LL _INF = 0xc0c0c0c0c0c0c0c0; const LL mod = (int)1e9+7; const int N = 1e5 + 100; int cnt[N]; char s[N]; LL ans[60][60]; int F[N], Finv[N], inv[N];/// F是階層 Finv是逆元的階層 void init(){ inv[1] = 1; for(int i = 2; i < N; i++) inv[i] = (mod - mod/i) * 1ll * inv[mod % i] % mod; F[0] = Finv[0] = 1; for(int i = 1; i < N; i++){ F[i] = F[i-1] * 1ll * i % mod; Finv[i] = Finv[i-1] * 1ll * inv[i] % mod; } } int comb(int n, int m){ /// C(n,m) if(m < 0 || m > n) return 0; return F[n] * 1ll * Finv[n-m] % mod * Finv[m] % mod; } int id(char ch){ if(islower(ch)) return ch - a + 1; return ch - A + 27; } int dp[N], tp[N]; void Ac(){ int n = strlen(s+1); int m = n / 2; for(int i = 1; i <= n; ++i) ++cnt[id(s[i])]; dp[0] = 1; for(int i = 1; i <= 52; ++i){ if(cnt[i]){ for(int j = m; j >= cnt[i]; --j) dp[j] = (dp[j] + dp[j-cnt[i]]) % mod; } } for(int i = 0; i <= m; ++i) tp[i] = dp[i]; for(int i = 1; i <= 52; ++i){ if(cnt[i] && cnt[i] <= m){ for(int j = cnt[i]; j <= m; ++j){ dp[j] = (dp[j] - dp[j-cnt[i]] + mod) % mod; } ans[i][i] = dp[m]; for(int j = 1; j <= 52; ++j){ if(cnt[j] && cnt[j] <= m && j != i){ for(int k = cnt[j]; k <= m; ++k){ dp[k] = (dp[k] - dp[k-cnt[j]] + mod)%mod; } ans[i][j] = dp[m]; for(int k = m; k >= cnt[j]; --k){ dp[k] = (dp[k] + dp[k-cnt[j]]) % mod; } } } for(int j = m; j >= cnt[i]; --j) dp[j] = tp[j]; } } LL zz = 2ll * F[m] * F[m] % mod; for(int i = 1; i <= 52; ++i) zz = (zz * Finv[cnt[i]]) % mod; int q, x, y; scanf("%d", &q); while(q--){ scanf("%d%d", &x, &y); printf("%I64d\n", zz * ans[id(s[x])][id(s[y])] % mod); } return ; } int main(){ init(); while(~scanf("%s", s+1)){ Ac(); } return 0; }
View Code

CF - 1111D Destroy the Colony DP