您的位置:首页 > 其它

TC Srm597 Div 1 T3

2015-06-18 07:56 246 查看
题意:

给出M,R,G,B,2M=R+B+G,M代表一个2*M区域的列数,RGB分别代码红绿蓝格子的个数,要求:每个2*2格子中,三种颜色每种至少有一个格子,且相邻格子颜色不同,问有多少种排列方式

首先我们发现可以把一列两格的放置方案分为两组,{RB,BG,GR},{BR,GB,RG}

一个合法方案必定只由其中的一组组成,因此我们可以计算一组的方案,然后将其×2即可

那么我们假设RB有x个,BG有y个,GR有z个,那么ans等价于:求使得BR,RG,GB分别不能与自己相邻的放置方案数。

我们假设x>y>z,首先我们要用 y,z去填补x之间的空缺,

如果y+z<x-1,则无法填补,返回0

否则,我们有4种方案,填中间x-1个,左边x个,右边x个,全部x+1个,我们对于x-1~x+1分别计算即可

那么现在有nx(nx=x+1/x/x-1)个空,我们要用y,z去填,

1.首先我们假设用y填y1个空,方案为C(nx,y-1),用z填z1=x-y1个空

2.设多出的y2=y-y1,把y2塞进去的方案等价于把所有的y分成 y1份的方案数,为C(y-1,y1-1)

对于每个多塞的y,我们要塞一个z来防止y相邻,那么塞完y后我们剩的z为z2=z-z1-y2,再将这些z分别插个y1个序列的两端,方案为C(2*y1,z2)

至此,分配结束

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>

using namespace std;

class LittleElephantAndBoard{
public:
int getNumber(int, int, int, int )
};

typedef long long ll;

int N=1000000;
int mo=1000000007;
int jc[1000011],fc[1000011];
int ans,tmp,ts,x,y,z,xl,yl,req,zl,dt,tj,M,R,G,B,j,i;

int mi(int x,int z)
{
int l;
l=1;
while(z){
if(z%2==1)l=(ll)l*x%mo;
x=(ll)x*x%mo;
z/=2;
}
return l;
}

int C(int n,int m)
{
return (ll)jc
*fc[m]%mo*fc[n-m]%mo;
}

int LittleElephantAndBoard::getNumber(int M,int R,int G,int B)
{
jc[0]=1;
for(i=1;i<=N;i++)jc[i]=(ll)jc[i-1]*i%mo;
fc
=mi(jc
,mo-2);
for(i=N-1;i>=0;i--)fc[i]=(ll)fc[i+1]*(i+1)%mo;
x=M-B;y=M-R;z=M-G;
if(x<0||y<0||z<0)return 0;
ans=0;
if(y>x)swap(x,y);
if(z>x)swap(x,z);
if(z>y)swap(y,z);
if(y+z<x-1)return 0;
for(xl=x-1;xl<=x+1;xl++){
if(y+z<xl)continue;
tmp=0;
for(j=1;j<=y;j++){
req=xl-j;
if(req>z)continue;
yl=y-j;
if(req+yl>z)continue;
ts=C(xl,j);
ts=(ll)ts*C(y-1,j-1)%mo;
zl=z-req-yl;
if(zl>2*j)continue;
ts=(ll)ts*C(2*j,zl)%mo;
tmp=(tmp+ts)%mo;
}
if(xl==x)tmp=tmp*2%mo;
ans=(ans+tmp)%mo;
}
ans=(ans*2)%mo;
return ans;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: