poj 3373

题目:http://poj.org/problem?id=3373

题意:给出2个整数nn<10^100)和kk<10000),求满足以下条件的整数m   1mn位数相同    2m能被k整除    3、满足以上两点时,mn在相同位置的地方,数字不同的个数最少    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 的余数

View Code
 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 }
posted @ 2012-08-10 20:23  AC_Girl  阅读(260)  评论(0编辑  收藏  举报