题意:给两个整数a、b,问a最少加上多少后,b成为a的子串。( 0 <= a <= 10^100, 0 <= b <= 10^7)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3925
——>>开始用C++<string>库中的find来找子串,结果TLE了,后来,枚举匹配位:
13464164643467464646 1836,
| | | | | | | |
| | | | 1836
1836
使4646变成1836,那么需要+ (11836 - 4646);(1836不够大,在前面补1,后面补0,这个数据刚刚好是最后一个位置,不用补0)
使1646变成1836,那么需要+ (18360000000000 -164643467464646 );(1836够大,后面补0就行)
但是上面的运算都是用字符串来运算的,而不是直接用 + - ;
从4开始,一直枚举到最左边的1;
WA,WA,WA……多少次,太痛苦了……
最后,发现我的程序测试几个40多位的a,7位的b都是正确的,有点意思了,再测,测,测……终于发现:当a长度比b的长度小时,没做处理,修改——>AC!
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 100 + 10; bool cmp(char *s, int high, int low, char *sub) //判断s[high]~s[low]是否就是字符串sub { int j = 0; for(int i = high; i <= low; i++) if(s[i] != sub[j++]) return 0; return 1; } int cmpp(char *a, char *b) //字符数组表示的a与b的大小比较 { int len_a = strlen(a), len_b = strlen(b), len = min(len_a, len_b), i; if(len_a != len_b) //在程序除去了前导0,这里可直接比较位数来确定谁大谁小 { if(len_a > len_b) return 1; else return -1; } else //位数相等时 { for(i = 0; i < len; i++) { if(a[i] > b[i]) return 1; //数a > b if(a[i] < b[i]) return -1; //数a < b } return 0; //如果上面没返回,那么a == b } } int to_int(char *s, int high, int low) //将字符数组s转换成整数 { int ret = 0; for(int i = high; i <= low; i++) ret = ret*10 + s[i]-'0'; return ret; } int main() { int i, j, k, u, v, cnt = 1, T; char a[maxn], b[maxn], B[maxn], c[maxn], minn[maxn]; //a, b为输入数组,B, c为过程中处理的中间数组,minn存最小值(结果) scanf("%d", &T); while(T--) { scanf("%s%s", a, b); int len_a = strlen(a), len_b = strlen(b); for(i = 0; i < maxn; i++) minn[i] = '9'; //初始化为最大 for(i = len_b; i < maxn; i++) b[i] = '0'; b[maxn-1] = 0; //为b后面赋0,下面减法用到 int bb = to_int(b, 0, len_b-1); //求b的值 if(len_a < len_b) //当子串长度比原串更长时,子串更大 { int aa = to_int(a, 0, len_a-1); printf("Case #%d: %d\n", cnt++, bb-aa); continue; } bool ok = 0; //匹配成功标志 for(i = len_a-len_b; i >= 0; i--) //从后往前一一模拟 { int aa = to_int(a, i, i+len_b-1); if(aa == bb) //剪枝,匹配成功时 { ok = 1; break; } else //匹配不成功时 { for(u = 0; u < maxn; u++) B[u] = b[u]; //取一个b到B,不能直接操作原数组! for(j = len_a-1, k = len_a-1-i; j >= i; j--, k--) { if(B[k] >= a[j]) c[k] = B[k] - a[j] + '0'; else //借位 { if(k-1 >= 0) B[k-1]--; c[k] = B[k] + 10 - a[j] + '0'; } } c[len_a-i] = 0; //设结束字符 for(v = 0; v < len_a-i; v++) if(c[v] != '0') break; //除去前导0 if(v != 0) for(u = 0; v <= len_a-i; u++,v++) c[u] = c[v]; if(cmpp(c, minn) < 0) for(u = 0; u <= len_a-i; u++) minn[u] = c[u]; //更新 } } if(ok) printf("Case #%d: %d\n", cnt++, 0); else //还要1次对“-1”位的模拟 { for(u = 0; u < maxn; u++) B[u] = b[u]; //取一个b到B,不能直接操作原数组! for(j = len_a-1, k = len_a; j >= 0; j--, k--) { if(B[k] >= a[j]) c[k] = B[k] - a[j] + '0'; else //借位 { B[k-1]--; c[k] = B[k] + 10 - a[j] + '0'; } } c[0] = B[0]; //存下第1位 c[len_a+1] = 0; //设结束字符 for(v = 0; v < len_a+1; v++) if(c[v] != '0') break; //除去前导0 if(v != 0) for(u = 0; v <= len_a+1; u++,v++) c[u] = c[v]; if(cmpp(c, minn) == -1) for(u = 0; u <= len_a+1; u++) minn[u] = c[u]; //更新 printf("Case #%d: %s\n", cnt++, minn); } } return 0; }