HDU5456 记忆化搜索

传送门

题意:给你n个火柴,能拼成几个A-B=C的等式

思路:可以转换位B+C=A,这个题不允许有前导零,0这个数也是不行的,我们 从个位开始同时对B,C进行搜索,看是否满足

状态表示是dp[n][B][C][carry]:表示还剩余n个火柴,B是否继续,C是否继续,这一位有没有进位。

#include
using namespace std;
typedef long long ll;
const int N=510;
int m;
ll dp[N][2][2][2], cost[]={6,2,5,5,4,5,6,3,7,6};

inline void add(ll &x, ll y){
    x+=y; x%=m; return;
}

ll dfs(int n, bool B, bool C, bool carry){
    ll &ret=dp[n][B][C][carry];
    if(~ret) return ret;
    if(n==0){
        if(!B&&!C&&!carry)
            return ret=1;
        else
            return ret=0;
    }

    ret=0;
    if(B&&C){
        for(int i=0; i<=9; i++)
        for(int j=0; j<=9; j++){
            int sum=cost[i]+cost[j]+cost[(i+j+carry)%10];
            if(sum>n) continue;
            add(ret, dfs(n-sum, B, C, (i+j+carry)/10));
            if(i) add(ret, dfs(n-sum, 0, C, (i+j+carry)/10));
            if(j) add(ret, dfs(n-sum, B, 0, (i+j+carry)/10));
            if(i&&j)  add(ret, dfs(n-sum, 0, 0, (i+j+carry)/10));
        }
    }
    else if(B&&!C){
        for(int i=0; i<=9; i++){
            int sum=cost[i]+cost[(i+carry)%10];
            if(sum>n) continue;
            add(ret, dfs(n-sum, B, 0, (i+carry)/10));
            if(i) add(ret, dfs(n-sum, 0, 0, (i+carry)/10));
        }
    }
    else if(!B&&C){
        for(int i=0; i<=9;  i++){
            int sum=cost[i]+cost[(i+carry)%10];
            if(sum>n) continue;
            add(ret, dfs(n-sum, 0, C, (i+carry)/10));
            if(i) add(ret, dfs(n-sum, 0, 0, (i+carry)/10));
        }
    }
    else{
        if(carry)
            ret=(n==cost[1]);
        else
            ret=(n==0);
    }
    return ret%=m;
}

int main(){
    int T, n, Cas=0;

    scanf("%d", &T);
    while(T--){
        scanf("%d%d", &n, &m);
        n-=3;
        memset(dp, -1, sizeof dp);
        printf("Case #%d: %lld\n", ++Cas, dfs(n, 1, 1, 0));
    }

    return 0;
}

 

你可能感兴趣的:(#,dp,#,深搜,#,记忆化dp)