题意:
给出一个字符串的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;
}