其他分享
首页 > 其他分享> > CF1111D Destroy the Colony 题解

CF1111D Destroy the Colony 题解

作者:互联网

Codeforces
Luogu

Description.

给定一个长度为偶数的字符串,每次询问可以重排成多少个本质不同的字符串,是关于 \(x\) 和 \(y\) 好的。
一个字符在字符串中定义为左倾的,当且仅当:

右倾同理,不是左倾也不是右倾的定义为中立。
一个字符串关于 \(x\) 和 \(y\) 是好的,当且仅当:

Solution.

首先不管限制 \(2\),那就是一个裸的背包。
答案是一个 \(\frac{\left(\frac n2!\right)^2}{\prod_{i}cnt_i!}\times val\times 2\)。
其中的 \(val\) 表示 \(\{cnt_i\}\) 背包出 \(\frac n2\) 的方案数,后面的 \(2\) 表示左右是可以颠倒的。
然后,我们再考虑加上第 \(2\) 个限制,我们发现,就相当于我们的 \(val\) 需要减去一定值。
我们考虑背包的“撤回”,因为这是方案数,\(+\) 号具有逆运算 \(-\),所以我们可以撤回。
至于怎么撤回,模拟背包最后一次的撤回即可,因为背包是和插入顺序无关,所以我们可以把每个物品都当做最后一个物品来撤回。
撤回一次的复杂度是 \(O(n)\) 的,总复杂度是 \(O(n\times Q)\) 的,原地爆炸。
考虑限制 \(2\) 其实只和字符有关,而本质不同的字符对只有 \((26\times 2)^2\) 种。
总复杂度变成了 \(O(4\times n \times \Sigma^2)\),可以通过此题。

Coding.

点击查看菜鸡代码
//是啊……你就是那只鬼了……所以被你碰到以后,就轮到我变成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<'0'||c>'9';c=getchar()) if(c=='-') f=1;
	for(;c>='0'&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	if(f) x=-x;
}/*}}}*/
const int P=1e9+7;int n,Q,dp[100005],fc[100005],fi[100005],f[100005];
int cn[55],dl[55][55];char ch[100005];
inline int gtid(char ch) {return ch<='Z'?ch-'A':ch-'a'+26;}
inline int ksm(int x,int q=P-2) {int r=1;for(;q;q>>=1,x=1ll*x*x%P) if(q&1) r=1ll*r*x%P;return r;}
inline int C(int n,int m) {return 1ll*fc[n]*fi[m]%P*fi[n-m]%P;}
int main()
{
	fc[0]=1,scanf("%s",ch+1);for(int i=1;i<=100000;i++) fc[i]=1ll*fc[i-1]*i%P;
	fi[100000]=ksm(fc[100000]);for(int i=100000;i;i--) fi[i-1]=1ll*fi[i]*i%P;
	n=strlen(ch+1)/2;for(int i=1;i<=n+n;i++) cn[gtid(ch[i])]++;
	int xs=1ll*fc[n]*fc[n]%P;for(int i=0;i<52;i++) if(cn[i]) xs=1ll*xs*fi[cn[i]]%P;
	dp[0]=1;for(int i=0;i<52;i++) if(cn[i]) for(int j=n;j>=cn[i];j--) dp[j]=(dp[j]+dp[j-cn[i]])%P;
	for(int i=0;i<52;i++) if(cn[i]) for(int j=0;j<52;j++) if(cn[j])
	{
		memcpy(f,dp,sizeof(f));for(int k=cn[i];k<=n;k++) f[k]=(f[k]-f[k-cn[i]]+P)%P;
		{if(i^j) for(int k=cn[j];k<=n;k++) f[k]=(f[k]-f[k-cn[j]]+P)%P;}dl[i][j]=dl[j][i]=f[n];
	}
	for(read(Q);Q--;) {int x,y;read(x),read(y),printf("%lld\n",2ll*xs*dl[gtid(ch[x])][gtid(ch[y])]%P);}
	return 0;
}

标签:字符,CF1111D,背包,int,题解,times,撤回,Destroy,dp
来源: https://www.cnblogs.com/pealfrog/p/15062922.html