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

abba
2
1 4
1 2

Sample Output

2
0

题解:这个题的每一部分都比较简单,加在一起就有难度了。关于组合数学的部分就不说了,比较简单,这个题的精华在于dp的部分,对于每次的询问,相当于强制让两种字符不在左边(或者不在右边),也就是在原始的dp递推方程中要跳过这两个字符的方案数,如果每次都重新递推,递推的复杂度是O(n * k),一共有k^2个组合,复杂度会炸,这时就要考虑利用之前dp的信息来减少递推的计算量,新的tmp_dp[j]的状态定义长度为j的,没有第i种字符的方案数,这其实就是长度为j的总方案数减去强制有第i种字符的方案数,而强制有i的方案数就应该是没有i的长度为j - cnt[i]的方案数,这恰好就是tmp_dp[j - cnt[i]],因此tmp[j] = dp[j] - tmp_dp[j - cnt[i]],可以在O(n)的时间内完成递推,一共有k^2个组合,因此复杂度时O(n * k^2),可以接受。

  1 #include <bits/stdc++.h>
  2
  3 using namespace std;
  4
  5 #define REP(i, n) for (int i = 1; i <= (n); i++)
  6 #define sqr(x) ((x) * (x))
  7
  8 const int maxn = 100000 + 10;
  9 const int maxm = 200000 + 100;
 10 const int maxs = 52;
 11
 12 typedef long long LL;
 13 typedef pair<int, int> pii;
 14 typedef pair<double, double> pdd;
 15
 16 const LL unit = 1LL;
 17 const int INF = 0x3f3f3f3f;
 18 const LL Inf = 0x3f3f3f3f3f3f3f3f;
 19 const double eps = 1e-14;
 20 const double inf = 1e15;
 21 const double pi = acos(-1.0);
 22 const LL mod = 1000000007;
 23
 24 inline int cal(char ch)
 25 {
 26     if (isupper(ch))
 27         return ch - ‘A‘ + 26;
 28     return ch - ‘a‘;
 29 }
 30
 31 LL pow_mod(LL x, LL n, LL mod)
 32 {
 33     LL ans = 1, base = x;
 34     while (n)
 35     {
 36         if (n & 1)
 37             ans = (ans * base) % mod;
 38         base = (base * base) % mod;
 39         n >>= 1;
 40     }
 41     return ans;
 42 }
 43
 44 void Add(LL &a, LL b)
 45 {
 46     a += b;
 47     if (a > mod)
 48         a -= mod;
 49 }
 50
 51 void Sub(LL &a, LL b)
 52 {
 53     a -= b;
 54     if (a < 0)
 55         a += mod;
 56 }
 57
 58 string str;
 59 LL n;
 60 LL cnt[maxs];
 61 LL fact[maxn], inv[maxn];
 62 LL dp[maxn], tmp_dp[maxn];
 63 LL ans[maxs][maxs];
 64
 65 int main()
 66 {
 67     ios::sync_with_stdio(false);
 68     cin.tie(0);
 69     //freopen("input.txt", "r", stdin);
 70     //freopen("output.txt", "w", stdout);
 71     cin >> str;
 72     n = str.size();
 73     for (int i = 0; i < n; i++)
 74     {
 75         cnt[cal(str[i])]++;
 76     }
 77     fact[0] = fact[1] = 1;
 78     for (LL i = 2; i <= n; i++)
 79     {
 80         fact[i] = (fact[i - 1] * i) % mod;
 81     }
 82     inv[n] = pow_mod(fact[n], mod - 2, mod);
 83     for (LL i = n - 1; i >= 0; i--)
 84     {
 85         inv[i] = (inv[i + 1] * (i + 1)) % mod;
 86     }
 87     LL num = (fact[n / 2] * fact[n / 2]) % mod;
 88     for (int i = 0; i < maxs; i++)
 89     {
 90         num = (num * inv[cnt[i]]) % mod;
 91     }
 92     dp[0] = 1;
 93     for (int i = 0; i < maxs; i++)
 94     {
 95         if (!cnt[i])
 96             continue;
 97         for (int j = n; j >= cnt[i]; j--)
 98         {
 99             Add(dp[j], dp[j - cnt[i]]);
100         }
101     }
102     for (int i = 0; i < maxs; i++)
103     {
104         ans[i][i] = dp[n / 2];
105     }
106     for (int i = 0; i < maxs; i++)
107     {
108         if (!cnt[i])
109             continue;
110         for (int i = 0; i <= n; i++)
111             tmp_dp[i] = dp[i];
112         for (int t = cnt[i]; t <= n; t++)
113         {
114             Sub(tmp_dp[t], tmp_dp[t - cnt[i]]);
115         }
116         for (int j = i + 1; j < maxs; j++)
117         {
118             if (!cnt[j])
119                 continue;
120             for (int t = cnt[j]; t <= n; t++)
121             {
122                 Sub(tmp_dp[t], tmp_dp[t - cnt[j]]);
123                 ans[i][j] = (2LL * tmp_dp[n / 2]) % mod;
124                 ans[j][i] = ans[i][j];
125             }
126             for (int t = n; t >= cnt[j]; t--)
127                 Add(tmp_dp[t], tmp_dp[t - cnt[j]]);
128         }
129     }
130     int q;
131     cin >> q;
132     int x, y;
133     while (q--)
134     {
135         cin >> x >> y;
136         int l = cal(str[x - 1]);
137         int r = cal(str[y - 1]);
138         cout << (num * ans[l][r]) % mod << "\n";
139     }
140     return 0;
141 }

原文地址:https://www.cnblogs.com/npugen/p/10801504.html

时间: 2024-10-10 14:55:44

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

Codeforces Round #556 (Div. 2) - D. Three Religions(动态规划)

Problem  Codeforces Round #556 (Div. 2) - D. Three Religions Time Limit: 3000 mSec Problem Description Input Output Sample Input 6 8abdabc+ 1 a+ 1 d+ 2 b+ 2 c+ 3 a+ 3 b+ 1 c- 2 Sample Output YESYESYESYESYESYESNOYES 题解:动态规划,意识到这个题是动态规划之后难点在于要优化什么东西,本题

CodeCraft-19 and Codeforces Round #537 (Div. 2) A - Superhero Transformation

题目描述 We all know that a superhero can transform to certain other superheroes. But not all Superheroes can transform to any other superhero. A superhero with name ss can transform to another superhero with name tt if ss can be made equal to tt by chan

CodeCraft-19 and Codeforces Round #537 (Div. 2) B. Average Superhero Gang Power

题目描述: Every superhero has been given a power value by the Felicity Committee. The avengers crew wants to maximize the average power of the superheroes in their team by performing certain operations. Initially, there are nn superheroes in avengers tea

CodeCraft-19 and Codeforces Round #537 (Div. 2)

A. Superhero Transformation 水题,注意两个字符串可能长度不相等. #include<bits/stdc++.h> #define clr(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int maxn=100010; map<char ,int >m; int main(){ m['a']=m['e']=m['i']=m['o']=m['u']=1;

[codeforces]Round #537 (Div. 2)E. Tree

题解:  q次查询每次查询k个点  k的总和不超过1e5  那就->虚树  这个题分为两部分  前面先对每次查询的点建虚树 其次计数  对于新树上的每个关键点(查询点)  他能影响的m的范围 必然大于以r为根的祖先节点的个数 然后我们单独考虑每个节点的贡献为 当前集合个数减去其祖先节点的个数  然后我们考虑把每个点按照dfs序的下标考虑贡献  转移分为两部分 1.当前元素加入直接构成一个新集合 2,当前元素加入可以加入到  m(当前集合个数)-祖先节点个数 #include <bits/std

【CodeCraft-19 and Codeforces Round #537 (Div. 2) C】Creative Snap

[链接] 我是链接,点我呀:) [题意] 横坐标1..2^n对应着2^n个复仇者的基地,上面有k个复仇者(位置依次给出). 你是灭霸你要用以下方法消灭这k个复仇者: 一开始你获取整个区间[1..2^n] 假设你当前获取的区间为[l,r] mid = (l+r)/2 那么你每次有两种选择 1.将整个区间全都毁掉,如果这个区间里没有复仇者,那么花费为A,否则花费为B复仇者个数区间长度 2.将区间分为[l,mid]和[mid+1,r]分开毁掉(即分别获取[l,mid]和[mid+1,r]这两个区间,然

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解

传送门 D. Destroy the Colony 首先明确题意:除了规定的两种(或一种)字母要在同侧以外,其他字母也必须在同侧. 发现当每种字母在左/右边确定之后,方案数就确定了,就是分组的方案数乘\(\frac{((n/2)!)^2}{\prod cnt_i!}\). 分组的方案数考虑DP,设\(dp_{i,j}\)为前\(i\)个字母,占了左边\(j\)个位置的方案数,则有: \[ dp_{i,j}=dp_{i-1,j-cnt_i}+dp_{i-1,j} \] 当\(i\)是指定字母时特判

Codeforces Round #424 (Div. 2) D. Office Keys(dp)

题目链接:Codeforces Round #424 (Div. 2) D. Office Keys 题意: 在一条轴上有n个人,和m个钥匙,门在s位置. 现在每个人走单位距离需要单位时间. 每个钥匙只能被一个人拿. 求全部的人拿到钥匙并且走到门的最短时间. 题解: 显然没有交叉的情况,因为如果交叉的话可能不是最优解. 然后考虑dp[i][j]表示第i个人拿了第j把钥匙,然后 dp[i][j]=max(val(i,j),min(dp[i-1][i-1~j]))   val(i,j)表示第i个人拿

Codeforces Round #424 (Div. 2) C. Jury Marks(乱搞)

题目链接:Codeforces Round #424 (Div. 2) C. Jury Marks 题意: 给你一个有n个数序列,现在让你确定一个x,使得x通过挨着加这个序列的每一个数能出现所有给出的k个数. 问合法的x有多少个.题目保证这k个数完全不同. 题解: 显然,要将这n个数求一下前缀和,并且排一下序,这样,能出现的数就可以表示为x+a,x+b,x+c了. 这里 x+a,x+b,x+c是递增的.这里我把这个序列叫做A序列 然后对于给出的k个数,我们也排一下序,这里我把它叫做B序列,如果我