简单的游戏(10进制轮廓线dp)

题目:

思路:考虑按顺序进行填充,当前位置只受上一个影响和左边的一个影响。

假设有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;
}

猜你喜欢

转载自blog.csdn.net/qq_40774175/article/details/84555357