你真的会加法吗?
Description
众所周知,LJ精通 1 + 11+1 和 1 + 21+2 , 这天他遇到一个简单的加法题,但这个加法有一个特殊的性质,它是不进位加法,
比如当是10进制时 987 + 643 = 520987+643=520 ,当一位大于 1010 的时候我们我们对其模 1010 ,取余数作为这位的值,kk 进制数同理。
现在给你 nn 个数 (1 \leq n \leq 1e5)(1≤n≤1e5),并且每个数最多只有 1010 位,然后给定一个 kk (2 \leq k \leq 10)(2≤k≤10) ,代表所有数都是 kk 进制数,
接下来有 qq 次询问 (1 \leq q \leq 1e5)(1≤q≤1e5) ,每次询问给你一个长度不超过 1010 的 kk 进制数,你需要在 nn 个数中找到一个数和它进行
不进位加法时所得到的值最大,输出这个最大值。佳爷觉得这题太水了,就出给同学们做了。
Input
第一行两个正整数 n (1 \leq n \leq 1e5), k (2 \leq k \leq 10)n(1≤n≤1e5), k(2≤k≤10) 。
第二行 nn 个整数,每个整数最多只有 1010 位。
第三行一个整数 qq ,(1 \leq q \leq 1e5)(1≤q≤1e5)
接下来有 qq 行,代表 qq 次询问,每次给你一个位数不超过 1010 的整数。
Output
输出有 qq 行,每行对应一个询问的所求的最大值
Sample Input 1
4 10
998
997
886
885
4
991
998
119
190
Sample Output 1
889
886
995
976
Hint
输入的数字可能含有前导 00
思路:
最小异或和的变形。就是在字典树每次找最高位相加和最小的那一个点走就好了。
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 1e5 + 7;
int ch[maxn * 12][12],tot = 1;
int n,k;
char a[20];
void insert(char *s) {
int u = 1;
int len = strlen(s + 1);
for(int i = 11;i >= 1;i--) {
int id;
if(i <= len) id = s[len - i + 1] - '0';
else id = 0;
if(!ch[u][id]) {
ch[u][id] = ++tot;
}
u = ch[u][id];
}
}
string query(char *s) {
string ans;
int u = 1;
int len = strlen(s + 1);
for(int i = 11;i >= 1;i--) {
int id;
if(i <= len) id = s[len - i + 1] - '0';
else id = 0;
int mx = -1,pos = 0;
for(int j = 0;j <= 9;j++) {
if(ch[u][j] && (j + id) % k > mx) {
mx = (j + id) % k;
pos = j;
}
}
ans += (char)(mx + '0');
u = ch[u][pos];
}
return ans;
}
int main() {
scanf("%d%d",&n,&k);
for(int i = 1;i <= n;i++) {
scanf("%s",a + 1);
insert(a);
}
string ans;
int m;scanf("%d",&m);
for(int i = 1;i <= m;i++) {
scanf("%s",a + 1);
ans = query(a);
int flag = 0;
for(int i = 0;i < ans.size();i++) {
if(ans[i] != '0') {
flag = 1;
for(int j = i;j < ans.size();j++) {
printf("%c",ans[j]);
}
printf("\n");
break;
}
}
if(!flag) printf("0\n");
}
return 0;
}