Hdu 6831 Fragrant numbers —— 暴力区间DP

This way

题意:

现在有一个循环数组s,循环节长度为10,循环串为1145141919
你可以选出长度为k的1~k这k个数进行操作:
按照原来顺序,插入四种运算符:
在这里插入图片描述
使得这k个数字经过运算之后值为n,问你看最短是多少

题解:

绝了一道暴力傻逼题我没做出来。
一开始写了一个错的打表,发现它所有数要么是-1,要么在13之内。于是用区间dp来做:
dp[i][j][k]表示区间第i到第j,运算结果为k的可能性。
然后枚举循环长度,枚举起点,枚举断点,枚举左区间运算答案,枚举右区间运算答案。
小小的continue却能优化很多很多,时间复杂度尚可。
在这里插入图片描述
爷吐了

#include
using namespace std;
const int N=13,M=5005;
int dp[N][N][M],a[N]={0,1,1,4,5,1,4,1,9,1,9,1,1},ans[M];
int main()
{
    for(int i=1;i<N;i++){
        int ret=0;
        for(int j=i;j<=min(N-1,i+3);j++){
            ret=ret*10+a[j];
            if(ret<M)dp[i][j][ret]=1;
        }
    }
    for(int len=2;len<N;len++){
        for(int i=1;i+len-1<N;i++){
            int j=i+len-1;
            for(int k=i;k<j;k++){
                for(int l=1;l<M;l++){
                    if(!dp[i][k][l])continue;
                    for(int m=1;m<M;m++){
                        if(!dp[k+1][j][m])continue;
                        if(l*m<M)dp[i][j][l*m]=1;
                        if(l+m<M)dp[i][j][l+m]=1;
                    }
                }
            }
        }
    }
    for(int i=1;i<N;i++)
        for(int j=1;j<M;j++)
            if(dp[1][i][j]&&!ans[j])
                ans[j]=i;
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        printf("%d\n",ans[n]?ans[n]:-1);
    }
    return 0;
}

你可能感兴趣的:(想法,dp)