
可以发现状态是三个三个的转移的
问题变为三种颜色固定数量,求相邻颜色不同的组合方案数
枚举开头的颜色A,另外两个颜色BC可以插在中间
有奇数和偶数的两种情况B,C,或者BC
然后讨论一下统计方案就行了
#include<bits/stdc++.h>
using namespace std;
int t,m,r,g,b,ans;
const int mod=1e9+7;
int fac[2000005],inv[2000005],two[2000005];
int moc(int x)
{
if(x>=mod) return x-mod;
return x;
}
long long fast(int x,int y)
{
int ans=1;
while(y)
{
if(y&1) ans=1ll*ans*x%mod;
x=1ll*x*x%mod;
y>>=1;
}
return ans;
}
int cc(int n,int k)
{
return 1ll*fac[n]*inv[k]%mod*inv[n-k]%mod;
}
int work(int n,int a,int b,int c)
{
if(a<=0) return 0;
int ans=0;
for(int g=a-1;g<=a;g++)
{
if(g<=0) continue;
for(int e=0;e<=g;e++)
{
if((g-e+b-c)&1) continue;
int ob=(g-e+b-c)/2;
int oc=g-e-ob;
if(ob<0||oc<0) continue;
if(n-a-g-e<0) continue;
if((n-a-g-e)&1) continue;
int r=(n-a-g-e)/2;
ans=moc(ans+1ll*cc(g+r-1,g-1)*cc(g-e,ob)%mod*cc(g,e)%mod*two[e]%mod);
}
}
return ans;
}
int solve(int m, int r, int g, int b)
{
fac[0]=1;
for(int i=1;i<=2000000;i++) fac[i]=1ll*fac[i-1]*i%mod;
inv[2000000]=fast(fac[2000000],mod-2);
for(int i=1999999;i>=0;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
two[0]=1;
for(int i=1;i<=2000000;i++) two[i]=moc(two[i-1]<<1);
r=m-r,g=m-g,b=m-b;
int ans=0;
ans=(ans+2ll*work(m,r,g,b))%mod;
ans=(ans+2ll*work(m,g,r,b))%mod;
ans=(ans+2ll*work(m,b,g,r))%mod;
return ans;
}
int main()
{
scanf("%d%d%d%d",&m,&r,&g,&b);
ans=solve(m,r,g,b);
printf("%d\n",ans);
return 0;
}

本文介绍了一种解决颜色固定数量下,求相邻颜色不同组合方案数的算法。通过枚举开头颜色并讨论奇数和偶数情况,使用动态规划和组合数学的方法,统计所有可能的组合方案。
1834

被折叠的 条评论
为什么被折叠?



