题目:
思路:考虑按顺序进行填充,当前位置只受上一个影响和左边的一个影响。
假设有5列,那么每一列用一个数来填充,最大是99999,最小是00000.
由于m<=6,所以最大状态是999999,可以直接从0开始枚举,到999999复杂度为1e6。
dp[sta][cur] 表示当状态为sta时的方案数,由于当前状态由前一个状态转移过来,所以cur只需要0或1就行。
思路和普通的二进制表示的轮廓线dp类似。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
typedef long long ll;
const int mod=1e9+7;
ll dp[maxn][2];
char s[10][10];
int isp[21] = {0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0};
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
scanf("%s",s[i]);
}
int sta=1;
for(int i=0;i<m;i++) sta*=10;
dp[0][0]=1;
int cur=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cur^=1;
for(int k=0;k<sta;k++)
{
dp[k][cur]=0;
}
for(int k=0;k<sta;k++)
{
int f=k/(sta/10);
int last=k%10;
if(dp[k][cur^1]==0) continue;
for(int add=0;add<10;add++)
{
if((s[i][j]=='?'||(s[i][j]=='0'+add))&&(!i||(isp[f+add]))&&(!j||isp[last+add])) //需要记录s[i][j]=='0'+add的原因是是因为要保留前一状态,因为你会发现,这个状态进行转移以后,其实值是没有变化的。
{
int kk=k-f*(sta/10);
kk=kk*10+add;
dp[kk][cur]+=dp[k][cur^1];
}
}
}
}
}
ll ans=0;
for(int i=0;i<sta;i++)
{
ans+=dp[i][cur];
}
printf("%lld\n",ans);
return 0;
}