第一次自己写,没什么思路,完全是暴搜,tle。后来问stone,他给了我一份他通过的代码,说只是一个记忆化搜索,但他的代码我琢磨了半天硬是没看懂。 昨天又自己尝试着写,差不多只是在第一次自己写的基础上加了个记忆化,结果就到top10了。 #include <iostream> int remember[101][10005];//很关键,不加这个就tle //remember[a][b]=c 表示 如果当前串的余数为b,剩余可替换次数为a,替换区间在c-1到0之内的所有替换方式都是不成立的 using namespace std; char str[101]; int for_mod[101][10],k,len,num[101],test[101]; void init() { for(int i=0;i<10;i++) for_mod[0][i]=i%k; for(int i=1;i<len;i++) for(int j=0;j<10;j++) for_mod[i][j]=(10*for_mod[i-1][j])%k;//for_mod这个东西很经典,这样在替换了某一位的数字后,只需要O(1)的时间就可以计算出新的余数 memset(remember,0,len*sizeof(remember[0])); } bool DFS(int left,int index,int mod)//剩余可替换次数 起点 当前余数 { if(mod==0) { for(int t=len-1;t>=0;t--) printf("%d",test[t]); printf("/n"); return true;; } if(remember[left][mod]>index||left==0) return false; int temp,floor; for(int i=index;i>=0;i--)//因为要保证在替换位数一样的情况下,数字最小,不得不采用了这么别扭的循环方式 { for(int j=0;j<num[i];j++) { if(i==len-1&&j==0) continue; temp=mod+for_mod[i][j]-for_mod[i][num[i]]; temp=temp%k; if(temp<0) temp+=k; test[i]=j; if(DFS(left-1,i-1,temp)) return true; } test[i]=num[i]; } for(int i=0;i<=index;i++) { for(int j=num[i]+1;j<10;j++) { temp=mod+for_mod[i][j]-for_mod[i][num[i]]; temp=temp%k; if(temp<0) temp+=k; test[i]=j; if(DFS(left-1,i-1,temp)) return true; } test[i]=num[i]; } remember[left][mod]=index+1; return false; } void solve() { int mod=0; for(int i=0;i<len;i++) { test[i]=num[i]=str[len-i-1]-'0'; mod=mod+for_mod[i][num[i]]; mod%=k; } for(int i=0;;i++) { if(DFS(i,len-1,mod)) return; } } int main() { while(scanf("%s",str)!=EOF) { scanf("%d",&k); len=strlen(str); init(); solve(); } return 0; }