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 \(i\)-th character of the string represents the type of villain in the \(i\)-th hole.

Iron Man can destroy a colony only if the colony arrangement is such that all villains of a certain type either live in the first half of the colony or in the second half of the colony.

His assistant Jarvis has a special power. It can swap villains of any two holes, i.e. swap any two characters in the string; he can do this operation any number of times.

Now Iron Man asks Jarvis \(q\) questions. In each question, he gives Jarvis two numbers \(x\) and \(y\). Jarvis has to tell Iron Man the number of distinct colony arrangements he can create from the original one using his powers such that all villains having the same type as those originally living in \(x\)-th hole or \(y\)-th hole live in the same half and the Iron Man can destroy that colony arrangement.

Two colony arrangements are considered to be different if there exists a hole such that different types of villains are present in that hole in the arrangements.

Input:

The first line contains a string \(s\) (\(2 \le |s| \le 10^{5}\)), representing the initial colony arrangement. String \(s\) can have both lowercase and uppercase English letters and its length is even.

The second line contains a single integer \(q\) (\(1 \le q \le 10^{5}\)) — the number of questions.

The \(i\)-th of the next \(q\) lines contains two integers \(x_i\) and \(y_i\) (\(1 \le x_i, y_i \le |s|\), \(x_i \ne y_i\)) — the two numbers given to the Jarvis for the \(i\)-th question.

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

Sample Input:

AAaa

2

1 2

1 3

Sample Output:

2

0

Sample Input:

abcd

1

1 3

Sample Output:

8

题目链接

题解:

有一个长为偶数\(n\)的字符串,只含大小写字母,你可以任意打乱这个字符串,\(q\)次询问,每次给一个\(x, y\),询问满足所有相同字符均在同一半侧(左半侧或右半侧)并且原串中\(x和y\)这两个位置的字符也均在同一侧的字符串种类数

首先考虑没有\(xy\)限制的情况

假设你选择了\(a\)种字符,出现次数之和为\(n/2\),那这\(a\)个字符在左边的方案数为\((n/2)! / (\prod_{i=1}^acnt_i!)\), 右边的字符方案数为\((n / 2)! / (所有不在a中的字符的出现次数的阶乘的累乘积)\), 总方案数为\(2*(n/2)!*(n/2)!/ (\prod_{ch = 'a'}^{'z'}cnt_{ch}! * \prod_{ch = 'A'} ^ {'Z'}cnt_{ch}!)\),这个数再乘以任选若干个字符总出现次数为\(n/2\)的方案数的一半就是答案(一半是因为选自身和自身的补集会重复计算)

现在考虑\(xy\),之前的选定\(a\)的方案数乘以(任选若干个不包括\(x和y\)的字符总出现次数为\(n/2\)的方案数)就是答案

注意到\(xy\)实际上只有\(52*52\)种,可以把它们都处理出来,运用退背包的方法可以\(O(52*52*n)\)处理出答案

一层退背包:(\(dp[i]\)表示不做限制次数和为\(i\)的方案数,\(g[j][i]\)表示不含\(j\)和为\(i\)的方案数)

\[g[j][i] = dp[i]\ \ \ (i < cnt[j])
\]

\[g[j][i] = dp[i] - g[j][i - cnt[j]]\ \ \ (i >= cnt[j])
\]

可以\(O(n*m)\)处理出所有的\(g\), (\(n\)为物品数,\(m\)为背包容量)

实际上用的使用不用再开一个数组\(g\), 从小到大更改\(dp\)就可以了,处理完再倒着还原

AC代码:

#include <bits/stdc++.h>
using namespace std; const int N = 1e5 + 10, mod = 1e9 + 7; long long qp(long long a, long long n, int m = mod) {
long long res = 1;
while(n) {
if(n & 1)
res = res * a % m;
a = a * a % m;
n >>= 1;
}
return res;
} long long fac[N], inv[N], res[55][55], num, dp[N];
int cnt[55], q, x, y, n;
char s[N]; int mp(int x) {
if('a' <= x && x <= 'z')
return x - 'a';
else
return x - 'A' + 26;
} void init() {
fac[1] = 1;
for(int i = 2; i < N; ++i)
fac[i] = fac[i - 1] * i % mod;
inv[N - 1] = qp(fac[N - 1], mod - 2, mod);
for(int i = N - 2; ~i; --i)
inv[i] = inv[i + 1] * (i + 1) % mod;
} int main() {
init();
scanf("%s%d", s, &q);
n = strlen(s);
for(int i = 0; i < n; ++i) {
cnt[mp(s[i])]++;
}
num = fac[n / 2] * fac[n / 2] % mod;
dp[0] = 1;
for(int i = 0; i < 52; ++i) {
if(cnt[i]) {
num = num * inv[cnt[i]] % mod;
for(int j = n; j >= cnt[i]; --j)
dp[j] = (dp[j] + dp[j - cnt[i]]) % mod;
}
}
for(int i = 0; i < 52; ++i) {
res[i][i] = dp[n / 2];
if(cnt[i]) {
for(int j = cnt[i]; j <= n; ++j)
dp[j] = (dp[j] - dp[j - cnt[i]] + mod) % mod;
for(int j = i + 1; j < 52; ++j) {
if(cnt[j]) {
for(int k = cnt[j]; k <= n; ++k) {
dp[k] = (dp[k] - dp[k - cnt[j]] + mod) % mod;
}
res[i][j] = res[j][i] = 2LL * dp[n / 2] % mod;
for(int k = n; k >= cnt[j]; --k) {
dp[k] = (dp[k] + dp[k - cnt[j]] + mod) % mod;
}
}
}
for(int j = n; j >= cnt[i]; --j)
dp[j] = (dp[j] + dp[j - cnt[i]] + mod) % mod;
}
}
while(q--) {
scanf("%d%d", &x, &y);
printf("%lld\n", num * res[mp(s[x - 1])][mp(s[y - 1])] % mod);
}
return 0;
}

Codeforces1111D Destroy the Colony 退背包+组合数的更多相关文章

  1. Codeforces 1111D Destroy the Colony 退背包 (看题解)

    第一次知道这种背包还能退的.... 我们用dp[ i ]表示选取若干个物品重量到达 i 的方案数. 如果我们g[ i ]表示不用第 x 个物品的, 然后选若干其他的物品到达 i 的方案数. if(i ...

  2. 【Codeforces1111D_CF1111D】Destroy the Colony(退背包_组合数学)

    题目: Codeforces1111D 翻译: [已提交至洛谷CF1111D] 有一个恶棍的聚居地由几个排成一排的洞穴组成,每一个洞穴恰好住着一个恶棍. 每种聚居地的分配方案可以记作一个长为偶数的字符 ...

  3. BZOJ.2287.[POJ Challenge]消失之物(退背包)

    BZOJ 洛谷 退背包.和原DP的递推一样,再减去一次递推就行了. f[i][j] = f[i-1][j-w[i]] + f[i-1][j] f[i-1][j] = f[i][j] - f[i-1][ ...

  4. [CF1111D]Destroy the Colony

    题目大意:有一个长度为$n(n\leqslant10^5,n=0\pmod2)$的字符串,字符集大小为$52$,有$q(q\leqslant10^5)$次询问,每次询问第$x,y$个字符在这个字符串的 ...

  5. Codeforces 1111D(退背包、排列组合)

    要点 优质题解 因为只有某type坏人全部分布在同一撇时,才能一次消灭.所以题目安排完毕后一定是type(x)和type(y)占一半,其余占另一半. 实际情况只有52*52种,则预处理答案 枚举某两种 ...

  6. 01二重退背包+组合数学——cf1111d

    退背包进阶,还是挺难想的 /* dp1[k]表示取到体积k的方案数 dp2[i][j][k]表示左侧必选ij的情况下,取到体积k的方案数 dp2[i][j][k]=dp1[k]-左侧不选ij的方案数 ...

  7. 01退背包——bzoj2287

    退背包就是限制某一件物品不可取的方案数 先做出无限制的方案数,然后对于当前不可取的物品,dp2[j]表示不取改物品情况下,取得体积为j的方案数 有状态方程 dp2[j]=dp1[j]-dp2[j-w[ ...

  8. Destroy the Colony CodeForces - 1111D (可逆背包,计数)

    大意:给定字符串$s$, 保证长度为偶数, 给定q个询问, 每次询问给定两个位置$x$,$y$, 可以任意交换字符, 要求所有字符$s[x],s[y]$在同一半边, 剩余所有同种字符在同一半边的方案数 ...

  9. BZOJ3462 DZY Loves Math II 【多重背包 + 组合数】

    题目 输入格式 第一行,两个正整数 S 和 q,q 表示询问数量. 接下来 q 行,每行一个正整数 n. 输出格式 输出共 q 行,分别为每个询问的答案. 输入样例 30 3 9 29 1000000 ...

随机推荐

  1. 日志打印longging模块(控制台和文件同时输出)

    在把日志写入文件的同时在控制台输出 示例代码如下: #coding=utf-8 import logging import time import os dir = os.path.dirname(o ...

  2. VC++的project文件

    VC++的project文件说明: *.dsp:是VC++的项目文件,文本格式. *.dsw:是工作区文件,它能够指向一个或多个.dsp文件. *.clw:是 ClassWizard信息文件,实际上是 ...

  3. initializer_list、初始化列表、列表初始化

    什么是列表初始化 使用一个花括号来初始化变量,表现形式如下: std::vector<int>a{1,2,3,4,5}; 或者 std::vector<int>a = {1,2 ...

  4. 编译3.10内核 出现错误 “undefined reference to....&quot; 解决方法

    向内核中加入C文件后.假设想编译进内核须要改动当前文件夹下的Kconfig文件和Makefile文件. 如:加入一个test.c文件到driver文件夹下,则须要改动Kconfig文件: config ...

  5. ElasticSearch 分页检索

    在ElasticSearch的多索引和多类别里说到我们在集群中有14个文档匹配我们的(空)搜索语句.单数仅仅有10个文档在hits数组中.我们怎样看到其它文档? 和SQL使用LIMITkeyword返 ...

  6. JQGrid总记录数和查询消耗时间不显示

    其他做的几个页面都显示,只有一个不显示....百度发现, viewrecords选项未配置,应该设置为ture才可以.

  7. Windows server 2008 R2 如何启动任务计划程序

    使用windows server 2008 R2  的任务计划程序需要启动服务 Task Scheduler 服务, windows server 2008 R2 默认状态下Task Schedule ...

  8. 阿里 JAVA 开发手册 学习 4 工程规约

    应用分层 1.分层如下 1)开放接口层:可以直接封装Service接口暴露成RPC:通过web封装成http接口:网关控制层等. 2)终端显示层:各个端的模板渲染并执行显示层. 3)Web层:主要是度 ...

  9. Git检出远程库的分支等相关操作

    来到公司,询问同事后发现系统已经上传到Git远程仓库: 我这里先把远程仓库clone下来: $ git clone http://git.eas****tect.git 发现目录下只有一个READY. ...

  10. emWin 移植 - 基于红牛开发板

    一直想利用所学的东西自己设计一个精致一些的作品,手头正好有一块红牛开发板,就先用它来写一些软件,熟悉一下过程和一些想法的可行性.首先当然是选择一个操作系统了,对比了几种之后选择了emWin.那就移植一 ...