1. 程式人生 > >Problem E – Enigma(數位dp)

Problem E – Enigma(數位dp)

題意:

給一個1000位大數,有些位置用?遮住,給出這個大數的一個1000以內的因子k,求這個大數(多個輸出最小的,沒有輸出*)

解析:

這麼經典的數位dp居然沒想出來。

dp[i][j]i%k=jiixri1kdp[i+1][j]dp[i][(j+xr)%k]=xdp[i][j]表示到第i位為止可能\%k=j的第i位上的最小數\\設第i位上的數為x,r為i位上為1時對k的餘數\\顯然,dp[i+1][j]合法時,dp[i][(j+x*r)\%k]=x合法

ixri1kdp[i+1][j]dp[i][(j+xr)%k]=x

#include<bits/stdc++.h>
using namespace std;
#define LL long long

const LL mod=1e9+7;

char str[1009];
int k;
int remind[1009];
int dp[1009][1009];

int main(){
    scanf("%s%d",str,&k);
    int len=strlen(str);
    remind[len-1]=1%k;
    for
(int i=len-2;i>=0;i--){ remind[i]=remind[i+1]*10%k; } memset(dp,-1,sizeof(dp)); dp[len][0]=0; for(int i=len-1;i>=0;i--){ if(str[i]!='?'){ for(int j=0;j<k;j++){ if(dp[i+1][j]!=-1) dp[i][(j+(str[i]-'0')*remind[i])%k]=str[
i]-'0'; } } else{ for(int j=0;j<k;j++){ if(dp[i+1][j]!=-1) for(int num=0;num<=9;num++){ if(i==0&&num==0)continue; int to=(j+num*remind[i])%k; if(dp[i][to]==-1||dp[i][to]>num) dp[i][to]=num; } } } } if(dp[0][0]==-1)printf("*\n"); else{ int nex=0; for(int i=0;i<len;i++){ printf("%d",dp[i][nex]); nex=((nex-dp[i][nex]*remind[i])%k+k)%k;//上面求dp時的逆運算 } printf("\n"); } }