【动态规划】【数学思维】codeforces1111D Destroy the Colony

D. Destroy the Colony
time limit per test2 seconds
memory limit per test512 megabytes
inputstandard input
outputstandard output
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≤|s|≤105), 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≤q≤105) — the number of questions.

The i-th of the next q lines contains two integers xi and yi (1≤xi,yi≤|s|, xi≠yi) — the two numbers given to the Jarvis for the i-th question.

Output
For each question output the number of arrangements possible modulo 109+7.


 写完前三题还有一个小时时间,思考了一会儿之后滚去hack别人了,还不错,成功了三次。
 今天回头看这题,当时觉得难,后来看看题解觉得自己完全可以想到的。
 首先是题意理解问题,这题题意就有些坑,开始没看太明白,好在后来给了一次Clarification。说的是钢铁侠必须要选择类型和x,y两洞穴中类型相同的反派,把它们移动到殖民地的前半部或者后半部,并且剩余的反派,如果是同一类型,也要呆在同一边。问这样移动的方案数。(真是绕死了)
 隐含在题意中的一个信息是类型数最多52,因此,询问虽然达到了1E5,但去掉重复的,不会超过2704种。这很重要
 考虑x洞穴的类型tx,和y洞穴的类型ty,如果我们把类型分成两个集合,那么需要满足tx,ty在一个集合中,并且两个集合的洞穴总数必须相同,为n/2。如果我们有一个集合划分方案,那么就会得到W种方案( W = ( n 2 ! ) 2 ∑ c n t i 2 W=\frac{(\frac{n}{2}!)^2}{\sum cnt_i^2} W=cnti2(2n!)2,cnt表示每种类型的洞穴个数)
 到这里问题转化为求集合划分方案数,不考虑tx和ty的话,也就是求组成n/2大小的物品方案数,我们用dp计数就行了。考虑的话在原来结果上用减法去掉tx,ty就行了,一共2704种组合,先存起来再回答询问。
 效率 O ( n ∗ k 2 ) O(n*k^2) O(nk2)

#include
#include
#define mo 1000000007
using namespace std;
using LL=long long;

int n,q,fac[100005],x,y,tx,ty,cnt[53],dp[50005],ddp[50005],res[52][52],W;
char s[100005];

int quick_power(int x, int y)
{
	int res=1,base=x;
	while(y)
	{
		if(y&1)
			res=(LL)res*base%mo;
		base=(LL)base*base%mo;
		y>>=1;
	}
	return res;
}

int main()
{
	scanf("%s",s+1);
	n=strlen(s+1);
	scanf("%d",&q);
	fac[0]=1;
	for(int i=1;i<=n;i++)
		fac[i]=(LL)fac[i-1]*i%mo;
	for(int i=1;i<=n;i++)
		if(s[i]>='a')
			cnt[s[i]-'a'+26]++;
		else
			cnt[s[i]-'A']++;
	dp[0]=1;
	for(int i=0;i<52;i++)
		if(cnt[i])
			for(int j=n/2;j>=cnt[i];j--)
				dp[j]=(dp[j]+dp[j-cnt[i]])%mo;
	for(int tx=0;tx<52;tx++)
		for(int ty=0;ty<52;ty++)
		{
			for(int i=0;i<=n/2;i++)
				ddp[i]=dp[i];
			for(int i=cnt[tx];i<=n/2;i++)
				ddp[i]=(ddp[i]-ddp[i-cnt[tx]]+mo)%mo;
			if(tx!=ty)
				for(int i=cnt[ty];i<=n/2;i++)
					ddp[i]=(ddp[i]-ddp[i-cnt[ty]]+mo)%mo;
			res[tx][ty]=ddp[n/2];
		}
	W=(LL)fac[n/2]*fac[n/2]%mo;
	for(int i=0;i<52;i++)
		W=(LL)W*quick_power(fac[cnt[i]],mo-2)%mo;
	while(q--)
	{
		scanf("%d%d",&x,&y);
		if(s[x]>='a')
			tx=s[x]-'a'+26;
		else
			tx=s[x]-'A';
		if(s[y]>='a')
			ty=s[y]-'a'+26;
		else
			ty=s[y]-'A';
		printf("%lld\n",(LL)2*W*res[tx][ty]%mo);
	}
	return 0;
}

你可能感兴趣的:(Codeforces,数学思维,动态规划/递推)