CF1111D Destroy the Colony 题解
作者:互联网
Link.
Description.
给定一个长度为偶数的字符串,每次询问可以重排成多少个本质不同的字符串,是关于 \(x\) 和 \(y\) 好的。
一个字符在字符串中定义为左倾的,当且仅当:
- 在 \([\cfrac n2,n]\) 中不出现这个字符。
右倾同理,不是左倾也不是右倾的定义为中立。
一个字符串关于 \(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