http://poj.org/problem?id=3373
Changing Digits
Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 2719 | Accepted: 863 |
Description
Given two positive integers n and k, you are asked to generate a new integer, say m, by changing some (maybe none) digits of n, such that the following properties holds:
- m contains no leading zeros and has the same length as n (We consider zero itself a one-digit integer without leading zeros.)
- m is divisible by k
- among all numbers satisfying properties 1 and 2, m would be the one with least number of digits different from n
- among all numbers satisfying properties 1, 2 and 3, m would be the smallest one
Input
There are multiple test cases for the input. Each test case consists of two lines, which contains n(1≤n≤10100) and k(1≤k≤104, k≤n) for each line. Both n and k will not contain leading zeros.
Output
Output one line for each test case containing the desired number m.
Sample Input
2 2 619103 3219
Sample Output
2 119103
Source
POJ Monthly--2007.09.09, Rainer
[思路]:
看了别人的解题报告才写出来。一开始不知道怎么搜,没思路。
我们知道:假设k的位数是D,那么改变n的最后D+1位,能得到k+1的顺序数,由鸽巣原理,这k+1个数中至少有1个数能被k整除。所以,至多替换n的D+1位,肯定能找到结果。(1) 先搜比n小的数
(2)再搜比n的大的数 ,这样就能保证只要搜出结果来了,就一定是最小值。
(3) 改变替换的个数 。直接这样搜,会TLE。
进行剪枝,增加一数组f[110][10010];
f[i][j] = c 表示 i 位置,当前余数为 j 时,剩余替换次数为 c ,index 在区间[0,c-1]时都不成立。
【code】:
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 5 using namespace std; 6 7 #define N 110 8 #define NN 10010 9 10 char str[N]; 11 int mod[N][N],ans[N],num[N],f[N][NN]; 12 int k,len; 13 14 int dfs(int pos,int m,int cnt) 15 { 16 int i,j; 17 if(m==0) return 1; //当余数为0时,表示已经找到,返回1 18 if(pos<0||cnt<=f[pos][m]||cnt==0) return 0; 19 20 //从前面最高位开始,从小到大遍历,保证得到的ans最小 21 for(i=pos;i>=0;i--) 22 { 23 for(j=0;j<num[i];j++) 24 { 25 if(i==len-1&&j==0) continue; 26 ans[i] = j; 27 int res = (m-(mod[i][num[i]]-mod[i][j])+k)%k; //注意+k防止出现负数 28 if(dfs(i-1,res,cnt-1)) return 1; //进入下一层搜索 29 } 30 ans[i] = num[i]; //还原ans 31 } 32 33 //从后面最低位开始,从小到大遍历,保证得到的ans最小 34 for(i=0;i<=pos;i++) 35 { 36 for(j=num[i]+1;j<10;j++) 37 { 38 if(i==len-1&&j==0) continue; 39 ans[i] = j; 40 int res = (m+(mod[i][j]-mod[i][num[i]]))%k; 41 if(dfs(i-1,res,cnt-1)) return 1; 42 } 43 ans[i] = num[i]; //还原 44 } 45 f[pos][m] = cnt; 46 // cout<<pos<<" "<<m<<" "<<cnt<<endl; 47 return 0; 48 } 49 50 int main() 51 { 52 while(~scanf("%s",str)) 53 { 54 int i,j; 55 scanf("%d",&k); 56 memset(f,0,sizeof(int)*(k+1)); 57 len = strlen(str); 58 for(i=0;i<10;i++) mod[0][i]=i%k; 59 for(i=1;i<len;i++) 60 { 61 for(j=0;j<10;j++) 62 { 63 mod[i][j] = (mod[i-1][j]*10)%k; //mod[i][j]: j*(10^i) 对 K 的取余 值 64 } 65 } 66 int m=0; 67 for(i=0;i<len;i++) 68 { 69 ans[i]=num[i]=str[len-1-i]-'0'; 70 m = (m + mod[i][ans[i]])%k; //获得str除以k的余数m 71 } 72 for(i=1;i<=len;i++) if(dfs(len-1,m,i)) break; 73 for(i=len-1;i>=0;i--) printf("%d",ans[i]); 74 putchar(10); 75 } 76 return 0; 77 }