题意:题意:给定一个图,0是不能放的,然后现在有1X1和1X2方块,最后铺满该图,使得1X1使用次数在C到D之间,1X2次数随便,问有几种放法。
解题思路:对比了一下网上的写法,花了1500Ms,我的花了3000ms。主要还是因为位运算多了一些,回头试试简化一下。转移方程见代码注释。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll dp[2][24][1040];
char s[102][15];
int MOD=1000000007;
int main()
{
int now,pre;
//freopen("t.txt","r",stdin);
int n,m,c,d;
while (~scanf("%d%d%d%d", &n, &m, &c, &d))
{
memset(dp,0,sizeof(dp));
int maxs = (1<<m);
now=0,pre=1;
for(int i=1;i<=n;i++)
{
scanf("%s",s[i]+1);
}
dp[now][0][maxs-1]=1;
int r=~(1<<m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
swap(now,pre);
memset(dp[now],0,sizeof(dp[now]));
int tp = s[i][j] - '0';
if(tp)
{
for (int k = 0; k <=d; k++)
{
for (int t = 0; t < maxs; t++)
{
int g1= ((t<<1)&r)|1;
if (t&(1<<(m-1)))//上面已经放了
{
int g2=(((t|1)<<1)&r)|1,g3=((t<<1)&r);
dp[now][k+1][g1] = (dp[now][k+1][g1] + dp[pre][k][t]) % MOD;//放1X1
dp[now][k][g3] = (dp[now][k][g3] + dp[pre][k][t]) % MOD;//什么都不放
if((t&1)==0&&j>1)//左边没有放
dp[now][k][g2]=(dp[now][k][g2]+dp[pre][k][t])%MOD;//1*2左放
}
else//上面还没有放 1*2竖放
{
dp[now][k][g1]=(dp[now][k][g1]+dp[pre][k][t])%MOD;
}
}
}
}else
{
for (int k = 0; k <=d; k++)
{
for (int t = 0; t < maxs; t++)
{
int g1= ((t<<1)&r)|1;
if(t&(1<<(m-1)))//如果上面已经放了
{
dp[now][k][g1]=(dp[now][k][g1]+dp[pre][k][t])%MOD;
}
}
}
}
}
}
long long ans = 0;
for (int i = c; i <= d; i++)
ans = (ans + dp[now][i][maxs - 1]) % MOD;
printf("%lld\n", ans);
}
return 0;
}