题意:有n行格子,第i(1<=i<=n)行有i个格子,每行格子是左对齐。现在要在每一个格子填入一个非负整数,最后使得每一行每一列的和都不超过2。
请计算有多少种方案,答案比较大,请输出对100,000,007(1e8+7)取余后的结果。
这题跟bzoj1801很像,基本上就是一道题了,但是注意这个地方可以一次放2,但是那题不行,所以我们还要改一下。
设f[i][j][k]表示做到了第i行,和为1的有j列,和为2的有k列,那么转移的话有7种,除了原来的6种(不知道这6种的移步),还新加了一种,就是一次加2的情况:
f[i][j][k]+=f[i−1][j][k−1]∗(m−k−j+1)
然后把m都变为i就可以啦。
1A,爽啊。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
int n,m;
const int N=215;
const int mo=1e8+7;
typedef long long ll;
//int C[N][N];
ll f[N][N][N];
inline void add(ll &x,ll y)
{
x=(x+y)%mo;
}
int main()
{
//pre();
scanf("%d",&n);
memset(f,0,sizeof(f));
f[0][0][0]=1;
fo(i,1,n)
{
int m=i;
fo(j,0,m)
{
fo(k,0,m-j)
{
f[i][j][k]=f[i-1][j][k];
if (j>=1) (f[i][j][k]+=f[i-1][j-1][k]*(m-j-k+1))%=mo;
if (k>=1) (f[i][j][k]+=f[i-1][j+1][k-1]*(j+1))%=mo,(f[i][j][k]+=f[i-1][j][k-1]*(m-j-k+1))%=mo;
if (j>=2) (f[i][j][k]+=f[i-1][j-2][k]*(m-j-k+2)*(m-j-k+1)/2)%=mo;
if (k>=2) (f[i][j][k]+=f[i-1][j+2][k-2]*(j+2)*(j+1)/2)%=mo;
if (j>=1&&k>=1) (f[i][j][k]+=f[i-1][j][k-1]*(m-j-k+1)*j)%=mo;
}
}
}
ll ans=0;
fo(j,0,n)
fo(k,0,n-j)ans=(ans+1ll*f[n][j][k])%mo;
printf("%lld\n",ans);
}