Codeforces #848C: String Reconstruction 题解之花样虐题

显然的是,没有被赋过值的点,赋上a能保证字典序最小

不论何种方法,最终的目的是不要让一个位置被重复赋值


这题最重要的注意点是,区间可以从1e6开始,长度是1e6,所以字符串数组ans要开到2e6

另一个注意点是,对于要将所有字符串存下来做统一处理的做法,因为不确定每个字符串的长度,开的太大会mle,所以逼不得已要用string,裸的cin读入会超时

别忘了加ios::sync_with_stdio(false)


很容易想到的一个方法是将所有区间扔进数组按左端点排序

记录一个当前处理到的位置cur

如果当前区间左端点小于cur,就从cur更新到右端点(有可能cur也大于右端点,那就不更新跳过该区间)

如果左端点大于cur就老老实实更新

这样是O(2000000logn)的

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#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
#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<

另一个很容易想到的做法是用线段树

维护区间是否已经赋过值

不过这样有点overkill

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#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
#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<>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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#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
#define LOWBIT(x) x & (-x)
using namespace std;

set s;
set::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<


相似的思路,用dsu来维护可以大幅提升效率

一个点如果已经赋过值,就合并i和i+1

这种做法很像356B Knight Tournament

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include  
#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
#define LOWBIT(x) x & (-x)
using namespace std;

char s[1000048];
char ans[2000048];

int pre[2000048];
inline int find_anc(int x)
{
	//cout<<"*"<

有一种十分有趣的做法

对于每个区间i,在开始处打标记i,在结束处打标记-i

把每个位置扫一遍

开一个set表示包含了当前位置的那些区间

扫到位置i时,查看所有的标记,如果是正的,将该区间扔进set,如果是负的,将该区间扔出set

如果set是空的,赋上a

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define x first
#define y second
#define mp make_pair
#define pb push_back
#define LL long long
#define Pair pair
#define LOWBIT(x) x & (-x)
using namespace std;

const int INF=0x7ffffff;

int n;
string s[100048];
int len[100048];
char ans[2000048];
vector a[2000048];
set 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;j0) 
				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;
}



你可能感兴趣的:(DSU)