1. 程式人生 > >簡單的遊戲(10進位制輪廓線dp)

簡單的遊戲(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;
}