CSUST 4001-你真的會加法嗎?(不進位加法-字典樹)
題目連結:http://acm.csust.edu.cn/problem/4001
CSDN食用連結:https://blog.csdn.net/qq_43906000/article/details/107721754
Description
眾所周知,LJ精通 \(1+1\) 和 \(1 + 2\), 這天他遇到一個簡單的加法題,但這個加法有一個特殊的性質,它是不進位加法,
比如當是10進位制時 \(987 + 643 = 520\) ,當一位大於 \(10\) 的時候我們我們對其模 \(10\) ,取餘數作為這位的值,\(k\) 進位制數同理。
現在給你 \(n\) 個數 \((1 \leq n \leq 1e5)\),並且每個數最多隻有 \(10\)
接下來有 \(q\) 次詢問 \((1 \leq q \leq 1e5)\) ,每次詢問給你一個長度不超過 \(10\) 的 \(k\) 進位制數,你需要在 \(n\) 個數中找到一個數和它進行
不進位加法時所得到的值最大,輸出這個最大值。佳爺覺得這題太水了,就出給同學們做了。
Input
第一行兩個正整數 \(n (1 \leq n \leq 1e5)\), \(k (2 \leq k \leq 10)\)。
第二行 \(n\) 個整數,每個整數最多隻有 \(10\) 位。
第三行一個整數 \(q\)
接下來有 \(q\) 行,代表 \(q\) 次詢問,每次給你一個位數不超過 \(10\) 的整數。
Output
輸出有 \(q\) 行,每行對應一個詢問的所求的最大值
Sample Input 2
4 10
998
997
886
885
4
991
998
119
190
Sample Output 2
889
886
995
976
emmm,比賽的時候似乎想到了字典樹。。。不過好像就出現了一秒就被我拋了。。。然後我就一直用二分艹。。。。
QAQ要是我能堅定一下我的字典樹的話這題也就過了。。。
如果能夠看出是字典樹的話,我們就知道,字典樹的操作只有兩種,一個是insert,一個是find,那麼毫無疑問我們當然是直接將n個字串全部插入到字典樹裡面的,不過為了後面的計算,我們要將每個數字補足10位,這樣的話等會找的時候才能好找。
接下來找的話我們先預處理出每個數字在k進位制下的需要匹配的最大數的排名,我們爬鏈找就是按照這個排名順序來找的,如下所示:
ll find(char *s,int rt,int k) {
ll ans=0;
int ch[15];
int nb=0;
for(int i=0; s[i]; i++) {
int x=s[i]-'0';
for (int j=0; j<10; j++){//列舉排名
if (trie[rt][ranks[x][j]]) {
ch[nb++]=ranks[x][j]+x;
rt=trie[rt][ranks[x][j]];
break;
}
}
}
for (int i=0; i<10; i++){
ans=ans*10+(ch[i]%k);
}
return ans;
}
********
scanf ("%d%d",&n,&k);
for (int i=0; i<k; i++) {
for (int j=0; j<k; j++) {
ranks[i][j]=(k-1-i-j+k)%k;
}
}
於是,此題便結束了。。。。QAQ
以下是AC程式碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mac=2e6+10;
int trie[mac][12],mark[mac];
int ranks[12][12],tot=0;
void insert(char *s,int rt) {
for(int i=0; s[i]; i++) {
int x=s[i]-'0';
if(trie[rt][x]==0) { //現在插入的字母在之前同一節點處未出現過
trie[rt][x]=++tot; //字母插入一個新的位置
}
rt=trie[rt][x]; //為下個字母的插入做準備
}
mark[rt]=1; //對該節點標記為結束(代表再次鏈上以此字母為結尾的存在)
}
ll find(char *s,int rt,int k) {
ll ans=0;
int ch[15];
int nb=0;
for(int i=0; s[i]; i++) {
int x=s[i]-'0';
for (int j=0; j<10; j++){
if (trie[rt][ranks[x][j]]) {
ch[nb++]=ranks[x][j]+x;
rt=trie[rt][ranks[x][j]];
break;
}
}
}
for (int i=0; i<10; i++){
ans=ans*10+(ch[i]%k);
}
return ans;
}
char s[15],s1[15];
int main(int argc, char const *argv[])
{
int n,k;
scanf ("%d%d",&n,&k);
for (int i=0; i<k; i++){
for (int j=0; j<k; j++){
ranks[i][j]=(k-1-i-j+k)%k;
}
}
for (int i=1; i<=n; i++){
scanf ("%s",s);
int len=strlen(s);
if (len<10)
for (int j=0; j<10-len; j++)
s1[j]='0';
for (int j=10-len,cnt=0; j<10; j++,cnt++) s1[j]=s[cnt];
insert(s1,0);
}
int q;
scanf ("%d",&q);
while (q--){
scanf ("%s",s);
int len=strlen(s);
if (len<10)
for (int j=0; j<10-len; j++)
s1[j]='0';
for (int j=10-len,cnt=0; j<10; j++,cnt++) s1[j]=s[cnt];
ll ans=find(s1,0,k);
printf("%lld\n",ans);
}
return 0;
}