poj 3373
题目:http://poj.org/problem?id=3373
题意:给出2个整数n(n<10^100)和k(k<10000),求满足以下条件的整数m 1、m与n位数相同 2、m能被k整除 3、满足以上两点时,m和n在相同位置的地方,数字不同的个数最少 4、满足以上三点时,m值最小
题目里面那个mod(看的别人的)
定义数组mod[101][10],mod[i][j]=((10^i)*j)%k,先求出:
0 1 2 3 4 5 6 7 8 9 (%k)
0 10 20 30 40 50 60 70 80 90 (%k)
0 100 200 300 400 500 600 700 800 900 (%k)
.....
通过递推式mod[i][j]=(mod[i-1][j]*10)%k; 就能避免n次方的运算,节省时间。
这样如果一个串改变一个数后可以在 O(1)的时间内求出对 kmod 的余数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <math.h> 5 6 const int N = 110; 7 #define _clr(a,val) (memset(a,val,sizeof(a))) 8 typedef long long ll; 9 10 using namespace std; 11 12 int mod[N][10]; 13 int num[N],path[N]; 14 int rest[N][10010]; // rest[i][j] = k 表示搜索的区间是[0,i],当前串对 m 的取余为 j 时,剩余的允许改变的数字次数为 k 15 char str[N]; 16 int kmod,len; 17 void init() 18 { 19 int i,j; 20 for(i = 0; i < 10; i++) mod[0][i] = i % kmod; 21 for(i = 1; i < len; i++) 22 { 23 for(j = 0; j < 10; j++) 24 mod[i][j] = ((10 % kmod) * (mod[i - 1][j] % kmod)) % kmod; 25 } 26 } 27 int dfs(int pnum,int s,int pmod) // pnum:在区间 [0,s]内剩余允许改变的数字个数 s:当前搜索的区间[0,s] pmod:当前数字串对 k 求模的值 28 { 29 //cout<<"pnum = "<<pnum<<" "<<s<<" "<<pmod<<endl; 30 if(!pmod) 31 { 32 for(int i = len - 1; i >= 0; i--) printf("%d",path[i]); 33 printf("\n"); 34 return 1; 35 } 36 int tmod; 37 if(pnum == 0 || rest[pnum][pmod] > s) return 0; // 剪枝 当前剩余的改变次数为零,或者在搜索的区间内,且当前对数字串m对 kmod 取余为 pmod时,剩余的修改(使得pmod == 0)数字次数 大于 区间时。直接返回 38 for(int i = s; i >= 0; i--) // 搜索比n小的数字,此时为了搜索到的解 m 是最小的,应该从区间[0,s]的第s位开始向第0位搜索,因为在相同 pnum 情况下,把高位数字变小所得到的 m 值更小。 39 { 40 for(int j = 0; j < num[i]; j++) 41 { 42 if(i == len - 1 && j == 0) continue; 43 tmod = (pmod - (mod[i][num[i]] - mod[i][j]) + kmod) % kmod; // 当把 m 的第i位数字 m[i] 改为j时,我们已经有((10^i)*m[i])%k的值存放在数组mod[i][m[i]]中,又有((10^i)*j)%k的值存放在数组mod[i][j]中,那么把m值改小前后的变化值为(mod[i][m[i]]- mod[i][j]) 44 path[i] = j; 45 if(dfs(pnum - 1,i - 1,tmod)) return 1; 46 } 47 path[i] = num[i]; 48 } 49 for(int i = 0; i <= s; i++) // 搜索比 n 大的,应该从区间的开始搜索,这样能保证最小 50 { 51 for(int j = num[i] + 1; j < 10; j++) 52 { 53 if(i == len - 1 && j == 0) continue; 54 tmod = (pmod + (mod[i][j] - mod[i][num[i]])) % kmod; 55 path[i] = j; 56 if(dfs(pnum - 1,i - 1,tmod)) return 1; 57 } 58 path[i] = num[i]; 59 } 60 rest[pnum][pmod] = s + 1; 61 return false; 62 } 63 int main() 64 { 65 int i; 66 //freopen("data.txt","r",stdin); 67 while(scanf("%s",str) != EOF) 68 { 69 len = strlen(str); 70 scanf("%d",&kmod); 71 init(); 72 _clr(rest,0); 73 int tmod = 0; 74 for(i = 0; i < len; i++) 75 { 76 num[i] = path[i] = (str[len - 1 - i] - '0'); 77 tmod = (tmod + mod[i][num[i]]) % kmod; 78 } 79 i = 0; 80 while(1) 81 { 82 if(dfs(i++,len - 1,tmod)) break; 83 } 84 } 85 return 0; 86 }