zoukankan      html  css  js  c++  java
  • 【Luogu4448】 [AHOI2018初中组]球球的排列

    题意

    (n) 个球球,每个球球有一个属性值 。一个合法的排列满足不存在相邻两个球球的属性值乘积是完全平方数。求合法的排列数量对 (10^9+7) 取膜。

    (nle 300) (本题数据范围可扩大至 (nle 3000)) 。

    题解

    首先很显然,如果 (xy,yz) 是完全平方数,那么 (xz) 也是完全平方数。这样我们可以将球球分成若干组,每组的两两乘积都是完全平方数。

    那么问题转化为有若干球球,每个球球一个颜色,求满足相同颜色的球球不相邻的排列数。

    下设 (a_i) 为第 (i) 种颜色的球球个数, (m) 为颜色个数。

    我们考虑容斥。我们将连续颜色相同的小球球合并成一个大球球,设 (b_i) 为 合并后第 (i) 种颜色的球球的数量,那么答案即为 (b) 的可重排列数乘上每种颜色内部排列数 (displaystyle frac{(sum_{i=1}^mb_i)!}{prod_{i=1}^mb_i!} cdot prod_{i=1}^m a_i!) ,容斥系数用插板法计算,为 (displaystyle prod_{i=1}^m (-1)^{a_i-b_i} cdot inom{a_i-1}{b_i-1})

    考虑如何计算这个式子。设 (s=sum_{i=1}^m b_i) ,那么答案式子可转化为:

    [(-1)^{n-s} s!prod_{i=1}^{m}frac{inom{a_i-1}{b_i-1}cdot a_i!}{b_i!} ]

    我们考虑用 dp 计算后半部分式子。设 (f(i,j)) 表示前 (i) 个数, (sum_{x=1}^i b_x=j) 的方案数。枚举 (b_i=k) 转移:

    [f(i,j)=sum_{k=1}^{min(a_i,j)}f(i-1,j-k)cdot frac{inom{a_i-1}{k-1}cdot a_i!}{k!} ]

    最后按上面的式子枚举 (s) 容斥统计答案即可。

    dp 的复杂度看上去像 (n^3) ,实际上理性分析,复杂度为 (sum_{i=1}^n a_i (sum_{j=1}^i a_j) =O(n^2)) .

    code

    #include<cstdio>
    #include<cmath>
    typedef long long ll;
    const int N=305,Mod=1e9+7;
    int t[N],a[N],f[N][N],n,m,fac[N],inv[N],ans,v;
    inline int mul(int x, int y) {
    	return 1ll*x*y%Mod;
    }
    inline int po(int x, int y)
    {
    	int r=1;
    	while(y)
    	{
    		if(y&1) r=mul(r,x);
    		x=mul(x,x), y>>=1;
    	}
    	return r;
    }
    inline int C(int x, int y) {
    	return mul(mul(fac[x],inv[y]),inv[x-y]);
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1,x,j;i<=n;++i)
    	{
    		scanf("%d",&x);
    		for(j=1;j<=m;++j)
    			if(1ll*t[j]*x==(ll)sqrt(1ll*t[j]*x)*(ll)sqrt(1ll*t[j]*x))
    			{
    				++a[j];
    				break;
    			}
    		if(j>m) t[++m]=x,++a[m];
    	}
    	fac[0]=inv[0]=1;
    	for(int i=1;i<=n;++i) fac[i]=mul(fac[i-1],i);
    	inv[n]=po(fac[n],Mod-2);
    	for(int i=n-1;i;--i) inv[i]=mul(inv[i+1],i+1);
    	int ans=0,v=0;
    	f[0][0]=1;
    	for(int i=1;i<=m;++i)
    	{
    		v+=a[i];
    		for(int j=1;j<=v;++j)
    			for(int k=1;k<=a[i]&&k<=j;++k)
    				f[i][j]=(f[i][j]+mul(f[i-1][j-k],mul(C(a[i]-1,k-1),inv[k])))%Mod;
    	}
    	for(int i=1;i<=n;++i)
    	{
    		int t=mul(fac[i],f[m][i]);
    		(n-i&1)?ans=(ans+Mod-t)%Mod:ans=(ans+t)%Mod;
    	}
    	for(int i=1;i<=m;++i) ans=mul(ans,fac[a[i]]);
    	printf("%d",ans);
    }
    
    
  • 相关阅读:
    SoftWater——SDN+UnderWater系列论文一
    《面向对象程序设计》2018年春学期寒假及博客作业总结
    2017级面向对象程序设计——团队作业3
    2017级面向对象程序设计——团队作业2
    生活
    一文搞懂transform: skew
    如何实现css渐变圆角边框
    使用腾讯云的图片缩略图服务
    谈谈实现瀑布流布局的几种思路
    vue cli 3 那些事儿
  • 原文地址:https://www.cnblogs.com/farway17/p/10972387.html
Copyright © 2011-2022 走看看