codeforces 828 c String Reconstruction(扫描线+string)

106 篇文章 0 订阅
51 篇文章 0 订阅

题意:

给出一个字符串的n个子串,并且给出这n个子串在原串里出现的位置,现在让构造出一个字符串符合题目的给定的条件,并且字典序最小。


解题思路:

直接xjb填子串的话肯定是超时的,所以要想办法避免重复的填。

其实很简单,在每个位置上都放一个标记,标记这里有一个长度为len的子串,然后我们o(n)扫一遍就可以了,标记的时候可能有重复,我们留下len最长的那一个就可以。


然后标记的时候,你如果真的把整个字符串放上去,就mle了,可以先把n个字符串记录下来,然后只标记字符串对应的编号就可以。


一开始我以为记录n个字符串也存不下,所有mle之后直接就弃疗了,其实题目里说了字符串总长度不超过1e6,所以开1e5(n的范围)个string就可以记录下来了,毕竟string是动态内存的。


然后还存在一个上届问题,就是构造出来的字符串上届,字符串总长度不超过1e6,但是原字符串并没有说,但是题目又说了,子串出现的起始位置的不超过1e6,那么最后构造出来的字符串长度就一定不超过2e6了。范围也构造出来了。


这个题扫描线o(n)扫一遍处理其实蛮好想的,关键在于我没有好好读题,以为怎么存都存不下这么多字符串mle了,然后就弃疗了,然后上届也是要好好读题才能确定下来的。读题很重要啊!


代码:

#include <bits/stdc++.h>
#define ps push_back
using namespace std;
const int maxn=2e6+1e5;
char str[maxn];
struct node
{
    string s;
    int len;
}t[maxn];
int l[maxn];
char s[maxn];
vector<int>a[maxn];
int main()
{
    ios::sync_with_stdio(false);
    int n, i, j, k, pos, ma=0, e;
    cin>>n;
    for(i=0; i<n; i++)
    {
        cin>>t[i].s;

        t[i].len=(int)t[i].s.length();
        cin>>k;
        for(j=0; j<k; j++)
        {
//            scanf("%d", &pos);
            cin>>pos;
            ma=max(ma, pos+t[i].len-1);

            {
            if((int)a[pos].size()>0)
            {
                if(t[a[pos][0]].len<t[i].len)
                {
                    a[pos][0]=i;
                }
            }
            else a[pos].ps(i);
            }
        }
    }
    if(ma>maxn)return 0*printf("%d\n", ma);
    int tmp;
    for(i=1; i<=ma; i++)
    {
        if((int)a[i].size()>0)
        {
            tmp=a[i][0];
            for(j=0; j<t[tmp].len; j++, i++)
            {
                str[i]=t[tmp].s[j];
                if(j>0 && (int)a[i].size()>0 && t[a[i][0]].len>(t[tmp].len-j))break;
            }
            i--;
        }
        else str[i]='a';
    }
    str[i]='\0';
    cout<<str+1<<endl;
//    printf("%s\n", str+1);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值