• CF1111D Destroy the Colony 题解


    Codeforces
    Luogu

    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;
    }
    
  • 相关阅读:
    关于大文本(txt)导入sqlserver2008数据库的一点感想
    欲则不达
    记录下马上两年的大学吧
    osgi使用 equnix框架 Bridge方式搭建方法(部分来源于ibm网站)
    mavan deploy不出repository.xml
    在项目中使用maven私服
    playbook 若干问题
    Maven 3 Felix 4 Eclipse 的搭建与部署(部分转载自别人文章)
    wallwd
    很好的面试记录
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15062922.html
Copyright © 2020-2023  润新知