题意:给你n个字符串(1 <= n <= 1e5),给出m(1<= m <= 1e6)个这个子串(子串的长度len
0<= len <= 1e6)在所求串的起始位置k(1 <= k <= 1e6),最终输出字典序最小的所求串。
思路:并查集存储如果在这个位置,其实应该从哪个位置开始,就是用并查集并起来,数组至少开到1e6*2+10,。。。数组开小了tle了一早上。。。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 1e6+10;
int pre[maxn*10];
char ch[maxn],s[maxn*10];
int find(int x){
return x == pre[x]?x:pre[x] = find(pre[x]);
}
void join(int x,int y){
int fx = find(x);
int fy = find(y);
if(fx > fy)
pre[fy] = fx;
else
pre[fx] = fy;
}
int main(){
int n, m, Max;
memset(s, 0, sizeof(s));
for(int i = 0; i < maxn*10; i++) pre[i] = i;
scanf("%d",&n);
Max = 0;
for(int i = 1; i <= n; i++){
scanf("%s%d",ch, &m);
int len = strlen(ch), x;
while(m--){
scanf("%d",&x);
x--;
Max = max(Max, x + len);
for(int j = find(x); j < len + x; j = find(j+1)){
s[j] = ch[j - x];
join(j, len+x); //每个j之后都至少会在pre[len+x]结束
}
}
}
for(int i = 0; i < Max; i++){
if(s[i] == 0)
printf("a");
else
printf("%c",s[i]);
}
return 0;
}
思路:在无数次Tle没找到错之后,上网看到了一个代码,只考虑单个字符串里的重复,时间也很快。觉得好神奇,这样时间其实很快可能是数据的问题吧。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 2e6+10;
char ch[maxn], s[maxn];
int main(){
int n, m, Max = 0;
scanf("%d",&n);
memset(s, 0, sizeof(s));
while(n--){
scanf("%s%d",ch, &m);
int len = strlen(ch), t = -1, x;
while(m--){
scanf("%d",&x);
x--;Max = max(Max, len+x);
for(int i = max(t, x); i < len+x; i++) //t来标记单个字符串之前结束的位置,至少从这个字符串结束的位置开始
s[i] = ch[i - x];
t = len + x;
}
}
for(int i = 0; i < Max; i++){
if(s[i] == '\0')
printf("a");
else
printf("%c",s[i]);
}
return 0;
}