CF - 1111D Destroy the Colony DP

题目传送门

题意:

这个题目真的是最近遇到的最难读。

有一个长度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;
}

原文地址:https://www.cnblogs.com/MingSD/p/10354827.html

时间: 2024-10-15 08:21:45

CF - 1111D Destroy the Colony DP的相关文章

Codeforces1111D Destroy the Colony 退背包+组合数

Codeforces1111D 退背包+组合数 D. Destroy the Colony Description: There is a colony of villains with several holes aligned in a row, where each hole contains exactly one villain. Each colony arrangement can be expressed as a string of even length, where the

CodeCraft-19 and Codeforces Round #537 (Div. 2) - D. Destroy the Colony(动态规划+组合数学)

Problem  CodeCraft-19 and Codeforces Round #537 (Div. 2) - D. Destroy the Colony Time Limit: 2000 mSec Problem Description Input Output For each question output the number of arrangements possible modulo 10^9+7. Sample Input abba21 41 2 Sample Output

CF 463D Gargari and Permutations [dp]

给出一个长为n的数列的k个排列(1?≤?n?≤?1000; 2?≤?k?≤?5).求这个k个数列的最长公共子序列的长度 dp[i]=max{dp[j]+1,where j<i 且j,i相应的字符在k个排列中都保持同样的相对位置} #include <iostream> #include <vector> #include <cstring> #include <cstdio> #include <cmath> #include <al

cf 547B. Mike and Feet dp

题意: n个矩阵排成一排,n<=2e5,高度分别为hei[i],宽度为1 对于一些连续的矩阵,矩阵的size为矩阵的个数,矩阵的strength为这些矩阵中高度最低的那一个高度 求:for each x such that 1 ≤ x ≤ n the maximum strength among all groups of size x. 对于每一个矩阵,我们先求出这个矩阵的l,r l表示这个矩阵左边最靠近它的小于它的矩阵的下标 r表示这个矩阵右边最靠近它的小于它的矩阵的下标 即在区间(l,r)

CF 486D vailid set 树形DP

As you know, an undirected connected graph with n nodes and n - 1 edges is called a tree. You are given an integer d and a tree consisting of n nodes. Each node i has a value ai associated with it. We call a set S of tree nodes valid if following con

cf Beautiful numbers(数位dp)

Beautiful numbers Time Limit:4000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Practice CodeForces 55D Description Volodya is an odd boy and his taste is strange as well. It seems to him that a positive integer number i

CF 835D Palindromic characteristics(DP)

题目链接:http://codeforces.com/problemset/problem/835/D 题目: Palindromic characteristics of string s with length |s| is a sequence of |s| integers, where k-th number is the total number of non-empty substrings of s which are k-palindromes. A string is 1-p

[CF1111D]Destroy the Colony

题目大意:有一个长度为$n(n\leqslant10^5,n=0\pmod2)$的字符串,字符集大小为$52$,有$q(q\leqslant10^5)$次询问,每次询问第$x,y$个字符在这个字符串的同一侧,并且所有相同字符在字符串的同一侧的方案数. 题解:因为字符集大小只有$52$,所以本质不同的询问只有$52\times52$种,预处理. 发现若确定了左右各放那几种字符后方案数是一定的,为$\dfrac{\left(\dfrac n2!\right)^2}{\prod\limits_{i=1

CF 1042B. Vitamins(状压dp)

以此题开始进入学习状压dp~ 题目大意 输入每瓶维生素的价格以及所含维生素元素,若能买到包含abc三种维生素,输出所需最小价钱,否则输出-1. 题解 状压dp,每种维生素对应一位,求出数值7(即二进制111)所对应的价格 代码 1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 using namespace std; 5 6 int main() 7 { 8 int dp[8], tmp