【详细揭秘】多重集の交错排列
1. 题面
一个多重集,问相邻元素不相同的排列有多少个 .
2. 解法
Step 1. 容斥
为了方便,我们令这个多重集 \(M\) 有 \(m\) 中不同元素 \(a_1,a_2,\cdots,a_m\),并且各出现 \(n_1,n_2,\cdots,n_m\) 次 .
考虑容斥,于是问题变成求至少有 \(t\) 个同种元素构成的方案数 .
将「打破 \(t\) 个约束」看作「合并 \(t\) 个集合」的过程,即用捆绑法每次将两个元素合并成一个元素,那么合并之后看成多重集全排列即可 .
于是答案就是
Step 2. dp
转而枚举 \(n_i-b_i\)(下式中写为 \(c_i\)),则柿子变为
再令 \(s=\sum c_i\),则柿子化成
这个容斥系数 \((-1)^{n-s}\) 和 \(s!\) 都解决掉了,考虑计算后面的
我们枚举一个 \(\sum c_i\),这样 \(c_i\) 就有俩限制,于是可以背包 .
令 \(dp_{i,j}\) 为考虑前 \(i\) 个元素,且 \(\sum c_i=j\) 的答案,则
非常标准的背包转移 .
预处理组合数,则可以 \(O(n^2)\) 求解 .
3. [AHOI2018初中组]球球的排列
1. 题面
链接:https://www.luogu.com.cn/problem/P4448
给一个序列 \(\{a\}\),问有多少个排列 \(\{p\}\) 满足对于所有 \(2\le i<n\),有 \(a_{p_i-1}\cdot a_{p_i+1}\) 不为完全平方数 .
数据范围:\(a_i\le 10^9,\,n\le 300\) .
2. 解法
显然「完全平方」性质是有传递性的,即如果 \(xy,yz\) 均为完全平方数,则 \(xz\) 为完全平方数 .
所以说,就转换成了上面那个问题,但是要带标号 .
只需要把以前的柿子乘个阶乘即可(\(\prod\) 里面多乘个 \(n_i!\),显然 dp 转移方程里也该乘 \(n_i!\)).
这个题的代码:
using namespace std;
#define int long long // 去掉就 WA 一部分 qwq,我也不知道哪里忘改 long long 了 :(
typedef long long ll;
const int N=333,MOD=1e9+7;
int n;
ll a[N],r[N],sz[N],dp[N],tdp[N],tmp[N],fac[N],ifac[N],inv[N],ans;
template<typename T>
inline T sqr(const T& t){return t*t;}
bool issqr(ll a){return sqr((int)(sqrt(a)))==a;}
ll C(int m,int n){return (m<n)?0:fac[m]*ifac[n]%MOD*ifac[m-n]%MOD;}
void initC(int n)
{
fac[0]=ifac[0]=fac[1]=ifac[1]=inv[1]=1;
for (int i=2;i<=n;i++)
{
fac[i]=fac[i-1]*i%MOD;
inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
ifac[i]=ifac[i-1]*inv[i]%MOD;
}
}
signed main()
{
scanf("%lld",&n); initC(n);
for (int i=1;i<=n;i++) scanf("%lld",a+i);
for (int i=1;i<=n;i++) r[i]=i;
for (int i=1;i<=n;i++)
{
++sz[r[i]];
for (int j=i+1;j<=n;j++)
if (issqr(a[i]*a[j])) r[j]=r[i];
}
dp[0]=1; ll tot=0;
for (int i=1;i<=n;i++)
{
if (!sz[i]) continue;
for (int j=0;j<=tot;j++){tmp[j]=dp[j]; dp[j]=0;}
for (int j=0;j<sz[i];j++)
{
tdp[j]=ifac[sz[i]-j]*C(sz[i]-1,j)%MOD;
if (j&1) tdp[j]=MOD-tdp[j];
for (int k=0;k<=tot;k++) dp[j+k]=(dp[j+k]+tdp[j]*tmp[k])%MOD;
} tot+=sz[i]-1;
}
for (int i=0;i<=tot;i++) ans=(ans+dp[i]*fac[n-i])%MOD;
for (int i=1;i<=n;i++) ans=ans*fac[sz[i]]%MOD;
printf("%lld\n",ans);
return 0;
}
// 参考 https://www.luogu.com.cn/blog/skydogli/solution-p4448
以下是博客签名,正文无关
本文来自博客园,作者:Jijidawang,转载请注明原文链接:https://www.cnblogs.com/CDOI-24374/p/15149546.html
版权声明:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0)进行许可。看完如果觉得有用请点个赞吧 QwQ