1. 程式人生 > >【CZY選講·Hja的棋盤】

【CZY選講·Hja的棋盤】

sca toolbar tab a* open 現在 ifd -a cstring

題目描述?

Hja特別有錢,他買了一個×的棋盤,然後Yjq到這個棋盤來搞事。一開始所有格子都是白的,Yjq進行次行操作次列操作,所謂一次操作,是將對應的行列上的所有格子顏色取反。現在Yjq希望搞事之後棋盤上有個黑色格子,問Yjq 有多少種搞事的方法。?

數據範圍

1≤,,,≤100000,0≤≤×M

題解:
①先不考慮冗余操作(冗余操作定義:對同一個地方進行2次及以上操作)

②設對行進行x操作,對列進行y次操作,那麽得到等式:

mx+ny-2xy=S ----->枚舉x,則y=(S-mx)/(n-2x)

③那麽行上剩余(R-x)次操作,列上剩余(C-y)次操作。

④為了使這些不影響答案,那麽必須偶數地添加到任意位置,可以添加的次數為:

Timesx=(R-x)/2 Timesy=(C-y)/2

⑤剩下的就是組合數問題了,問題轉化為:將m個小球放入n個盒子裏,盒子可以多放,可以不放。

⑥此類組合數問題解法:先講小球擴大為(n+m)個,那麽問題轉化為每個盒子至少放一個小球的方案數——轉化為將(n+m)個數分成非空的n組的問題(插隔板問題)。

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

using namespace std;

#ifdef unix
#define LL "%lld"
#else
#define LL "%I64d"
#endif

const int maxn=100010;
const int mo=1000000007;

int n,m,r,c,ans,v0[maxn],v1[maxn],v2[maxn],v3[maxn],v4[maxn];

long long s;

int multi(long long a,int b)
{
	a*=b;
	if (a>=mo) a%=mo;
	return (int)a;
}

void inc(int &a,int b)
{
	a+=b;
	if (a>=mo) a-=mo;
}

int mul(int a,int b)
{
	int ans=1;
	while (b)
	{
		if (b&1) ans=multi(ans,a);
		a=multi(a,a);
		b>>=1;
	}
	return ans;
}

int main()
{
	//freopen("c.in","r",stdin);
	//freopen("c.out","w",stdout);

	scanf("%d%d%d%d" LL,&n,&m,&r,&c,&s);
	v1[0]=1;
	for (int a=1;a<=100000;a++)
		v0[a]=mul(a,mo-2);
	int tmp=1;
	for (int a=0;a<=(r>>1);a++)
	{
		v1[a]=tmp;
		tmp=multi(tmp,multi(a+n,v0[a+1]));
	}
	tmp=1;
	for (int a=0;a<=(c>>1);a++)
	{
		v2[a]=tmp;
		tmp=multi(tmp,multi(a+m,v0[a+1]));
	}
	tmp=1;
	for (int a=0;a<=n;a++)
	{
		v3[a]=tmp;
		tmp=multi(tmp,multi(n-a,v0[a+1]));
	}
	tmp=1;
	for (int a=0;a<=m;a++)
	{
		v4[a]=tmp;
		tmp=multi(tmp,multi(m-a,v0[a+1]));
	}
	for (int a=r&1;a<=min(n,r);a+=2)
		if (a*2!=n)
		{
			if (((s-(long long)a*m))%(n-a*2)) continue;
			int b=(int)((s-(long long)a*m)/(n-a*2));
			if (b>c || b<0 || ((c-b)&1)) continue;
			int nowans=v3[a];
			nowans=multi(nowans,v1[(r-a)>>1]);
			nowans=multi(nowans,v4[b]);
			nowans=multi(nowans,v2[(c-b)>>1]);
			inc(ans,nowans);
		}
		else
		{
			if ((long long)a*m!=s) continue;
			int nowans=v3[a];
			nowans=multi(nowans,v1[(r-a)>>1]);
			int cnt=0;
			for (int b=(c&1);b<=min(r,c);b+=2)
				inc(cnt,multi(v4[b],v2[(c-b)>>1]));
			inc(ans,multi(ans,cnt));
		}
	printf("%d\n",ans);

	return 0;
}//czy020202(代碼有點醜)

別害怕我就站在你身邊,心在一起愛會讓我們勇敢。

別害怕我就站在你身邊,看黑夜無法吞沒黎明的天。——————汪峰《直到永遠》

【CZY選講·Hja的棋盤】