并查集 String Reconstruction CodeForces - 828C

题目

题意:给你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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值