显然的是,没有被赋过值的点,赋上a能保证字典序最小
不论何种方法,最终的目的是不要让一个位置被重复赋值
这题最重要的注意点是,区间可以从1e6开始,长度是1e6,所以字符串数组ans要开到2e6
另一个注意点是,对于要将所有字符串存下来做统一处理的做法,因为不确定每个字符串的长度,开的太大会mle,所以逼不得已要用string,裸的cin读入会超时
别忘了加ios::sync_with_stdio(false)
很容易想到的一个方法是将所有区间扔进数组按左端点排序
记录一个当前处理到的位置cur
如果当前区间左端点小于cur,就从cur更新到右端点(有可能cur也大于右端点,那就不更新跳过该区间)
如果左端点大于cur就老老实实更新
这样是O(2000000logn)的
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <utility>
#include <map>
#include <stack>
#include <set>
#include <vector>
#include <queue>
#include <deque>
#include <sstream>
#include <bitset>
#define x first
#define y second
#define mp make_pair
#define pb push_back
#define LL long long
#define ld long double
#define Pair pair<int,int>
#define LOWBIT(x) x & (-x)
using namespace std;
string s[100048];
int n;
Pair a[2000048];int top=0;
char ans[2000048];
int main ()
{
int i,j,num,x,mx=-1,l;
ios::sync_with_stdio(false);
cin>>n;
for (i=1;i<=n;i++)
{
cin>>s[i]>>num;
l=s[i].size();
for (j=1;j<=num;j++)
{
cin>>x;
a[++top]=mp(x,i);
mx=max(mx,x+l-1);
}
}
sort(a+1,a+top+1);
int cur=1,pp,ed;
for (i=1;i<=top;i++)
{
pp=max(cur,a[i].x);
ed=a[i].x+s[a[i].y].size()-1;
for (j=pp;j<=ed;j++)
ans[j]=s[a[i].y][j-a[i].x];
cur=max(cur,ed+1);
}
for (i=1;i<=mx;i++) if (!isalpha(ans[i])) cout<<'a'; else cout<<ans[i];
cout<<'\n';
return 0;
}
另一个很容易想到的做法是用线段树
维护区间是否已经赋过值
不过这样有点overkill
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <utility>
#include <map>
#include <stack>
#include <set>
#include <vector>
#include <queue>
#include <deque>
#include <sstream>
#include <bitset>
#define x first
#define y second
#define mp make_pair
#define pb push_back
#define LL long long
#define ld long double
#define Pair pair<int,int>
#define LOWBIT(x) x & (-x)
using namespace std;
int n,x;
char s[1000048];
char ans[2000048];
struct node
{
int left,right;
bool flushed;
}tree[6000048];
void build(int cur,int left,int right)
{
tree[cur].left=left;tree[cur].right=right;tree[cur].flushed=false;
if (left!=right)
{
int mid=(left+right)>>1;
build(cur*2,left,mid);
build(cur*2+1,mid+1,right);
}
}
void update(int cur,int left,int right)
{
if (tree[cur].flushed) return;
if (tree[cur].left==tree[cur].right)
{
ans[tree[cur].left]=s[tree[cur].left-x];
//cout<<tree[cur].left-x<<' '<<s[tree[cur].left-x]<<endl;
tree[cur].flushed=true;
return;
}
int mid=(tree[cur].left+tree[cur].right)>>1;
if (left<=mid) update(cur*2,left,right);
if (mid+1<=right) update(cur*2+1,left,right);
if (tree[cur*2].flushed && tree[cur*2+1].flushed) tree[cur].flushed=true;
}
int main ()
{
int i,j,num,len,mx=-1;
scanf("%d",&n);
build(1,1,2000000);
for (i=1;i<=n;i++)
{
scanf("%s%d",s,&num);
len=strlen(s);
for (j=1;j<=num;j++)
{
scanf("%d",&x);
mx=max(mx,x+len-1);
update(1,x,x+len-1);
}
}
for (i=1;i<=mx;i++) if (!isalpha(ans[i])) ans[i]='a';
printf("%s",ans+1);
printf("\n");
return 0;
}
一个比较标准的解法是用set
开一个set来维护还没有赋值过的位置
每次读入一个l,r以后,用lower_bound来查找区间内没有被赋值的点,赋值以后从set里扔出去
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <utility>
#include <map>
#include <stack>
#include <set>
#include <vector>
#include <queue>
#include <deque>
#include <sstream>
#include <bitset>
#define x first
#define y second
#define mp make_pair
#define pb push_back
#define LL long long
#define ld long double
#define Pair pair<int,int>
#define LOWBIT(x) x & (-x)
using namespace std;
set<int> s;
set<int>::iterator iter;
char ans[2000048];
char ss[1000048];
bool visited[2000048];
int n;
int ddd[2000048],top=0;
int main ()
{
int i,u,len,num,starter;
scanf("%d",&n);
//double t=GetTickCount();
for (i=1;i<=2000010;i++) s.insert(i);
//cout<<GetTickCount()-t<<endl;
for (u=1;u<=n;u++)
{
//cout<<i<<endl;
scanf("%s%d",ss,&num);
//cout<<ss<<endl<<num<<endl;
len=strlen(ss);
for (i=1;i<=num;i++)
{
scanf("%d",&starter);
iter=s.lower_bound(starter);
top=0;
for (;iter!=s.end() && *iter-starter+1<=len;iter++)
{
ans[*iter-1]=ss[*iter-starter];
visited[*iter]=true;
ddd[++top]=*iter;
//cout<<u<<' '<<i<<' '<<*iter<<endl;
//s.erase(*iter);
//cout<<*iter<<endl;
//iter++;
//cout<<*iter<<endl;
}
for (int j=1;j<=top;j++) s.erase(ddd[j]);
//puts(ans);
}
}
int length=2000010;
while (!visited[length]) length--;
for (i=0;i<=length-1;i++) if (!isalpha(ans[i])) ans[i]='a';
puts(ans);
return 0;
}
一个点如果已经赋过值,就合并i和i+1
这种做法很像356B Knight Tournament
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <utility>
#include <map>
#include <stack>
#include <set>
#include <vector>
#include <queue>
#include <deque>
#include <sstream>
#include <bitset>
#define x first
#define y second
#define mp make_pair
#define pb push_back
#define LL long long
#define ld long double
#define Pair pair<int,int>
#define LOWBIT(x) x & (-x)
using namespace std;
char s[1000048];
char ans[2000048];
int pre[2000048];
inline int find_anc(int x)
{
//cout<<"*"<<endl;
//cout<<x<<endl;
if (x!=pre[x]) pre[x]=find_anc(pre[x]);
return pre[x];
}
inline void update(int x,int y)
{
x=find_anc(x);y=find_anc(y);
pre[x]=y;
}
int main ()
{
int i,n,num,starter,len,mx=-1;
for (i=1;i<=2000010;i++) pre[i]=i;
scanf("%d",&n);
for (int u=1;u<=n;u++)
{
scanf("%s%d",s,&num);
len=strlen(s);
for (int t=1;t<=num;t++)
{
scanf("%d",&starter);
//cout<<t<<endl;
mx=max(mx,starter+len-1);
//cout<<t<<' '<<starter<<endl;
for (i=find_anc(starter);i-starter+1<=len;i=find_anc(i))
{
//cout<<i<<endl;
ans[i-1]=s[i-starter];
update(i,i+1);
}
}
}
for (i=0;i<=mx-1;i++) if (!isalpha(ans[i])) ans[i]='a';
puts(ans);
return 0;
}
有一种十分有趣的做法
对于每个区间i,在开始处打标记i,在结束处打标记-i
把每个位置扫一遍
开一个set表示包含了当前位置的那些区间
扫到位置i时,查看所有的标记,如果是正的,将该区间扔进set,如果是负的,将该区间扔出set
如果set是空的,赋上a
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <utility>
#include <map>
#include <stack>
#include <set>
#include <vector>
#include <queue>
#include <deque>
#define x first
#define y second
#define mp make_pair
#define pb push_back
#define LL long long
#define Pair pair<int,int>
#define LOWBIT(x) x & (-x)
using namespace std;
const int INF=0x7ffffff;
int n;
string s[100048];
int len[100048];
char ans[2000048];
vector<int> a[2000048];
set<Pair> ss;
int main ()
{
ios::sync_with_stdio(false);
int i,j,num,x,mx=-1;
cin>>n;
for (i=1;i<=n;i++)
{
cin>>s[i]>>num;
len[i]=s[i].size();
for (j=1;j<=num;j++)
{
cin>>x;
a[x].pb(i);
a[x+len[i]].pb(-i);
mx=max(mx,x+len[i]-1);
}
}
for (i=1;i<=mx;i++)
{
for (j=0;j<a[i].size();j++)
{
if (a[i][j]>0)
ss.insert(mp(a[i][j],i));
else
ss.erase(mp(-a[i][j],i-len[-a[i][j]]));
}
if (ss.size()==0)
ans[i]='a';
else
{
Pair res=*ss.begin();
ans[i]=s[res.x][i-res.y];
}
}
puts(ans+1);
return 0;
}