码迷,mamicode.com
首页 > 其他好文 > 详细

[BZOJ4278]Tasowanie

时间:2018-03-04 13:04:25      阅读:159      评论:0      收藏:0      [点我收藏+]

标签:AC   else   str   mem   output   ems   ==   etc   info   

题目本来是挺简单的,可惜我的常数太大,用了各种黑科技才A掉

把$A$和$B$拼到一起,中间和最后加一个无穷大的分隔符,求出后缀数组之后根据$rank$贪心取即可

如果不在末尾加分隔符,可以看一看这组数据

3
2 1 1
2
2 1

拼起来后是$[2,1,1,\infty,2,1]$,此时后缀$[2,1]$小于后缀$[2,1,1,\infty,2,1]$,先取了$[2,1]$,然而更优解是先取$[2,1,1,\infty,2,1]$

如果在末尾加一个分隔符,拼起来后是$[2,1,1,\infty,2,1,\infty$,此时后缀$[2,1,1,\infty,2,1,\infty]$就排在$[2,1,\infty]$前面了

这样做的原理是假如当前取到$A,B$,$A$是$B$的前缀且$A$是第二个字符串的后缀,那么如果$B$比$A$多的部分都是很小的数,先把$B$取完是更优的,也就是说我们让$A$的末尾变为无穷大,那么就可以让$B$排在$A$前面

代码常数太大,用了输入输出优化才卡过去

技术分享图片

技术分享图片

???

#include<stdio.h>
#include<string.h>
int s[400010],rk[800010],cnt[400010];
struct pr{
	int c[2],id;
	pr(int a=0,int b=0,int d=0){c[0]=a;c[1]=b;id=d;}
}p[400010],q[400010];
bool operator!=(pr a,pr b){return a.c[0]!=b.c[0]||a.c[1]!=b.c[1];}
int max(int a,int b){return a>b?a:b;}
void sort(int n,int f){
	int i,m=0;
	memset(cnt,0,sizeof(cnt));
	for(i=1;i<=n;i++){
		cnt[p[i].c[f]]++;
		m=max(m,p[i].c[f]);
	}
	for(i=1;i<=m;i++)cnt[i]+=cnt[i-1];
	for(i=n;i>0;i--)q[cnt[p[i].c[f]]--]=p[i];
	for(i=1;i<=n;i++)p[i]=q[i];
}
void suf(int n){
	int i,l,m;
	for(i=1;i<=n;i++)rk[i]=s[i];
	for(l=1;l<=n;l<<=1){
		for(i=1;i<=n;i++)p[i]=pr(rk[i],rk[i+l],i);
		sort(n,1);
		sort(n,0);
		m=0;
		for(i=1;i<=n;i++){
			if(p[i]!=p[i-1])m++;
			rk[p[i].id]=m;
		}
	}
}
int rd(){
	char c;
	int x=0;
	for(c=getchar();c>‘9‘||c<‘0‘;c=getchar());
	x=c-‘0‘;
	for(c=getchar();c<=‘9‘&&c>=‘0‘;c=getchar())x=x*10+c-‘0‘;
	return x;
}
namespace output {
    char s[2500000];
	char *t=s;
    inline void put(int x){
        if(x==0)*t++=‘0‘;
        else{
            static int a[5];
			int n=0;
            for(;x>0;x/=10)a[++n]=x%10;
            while(n>0)*t++=‘0‘+a[n--];
        }
        *t++=‘ ‘;
    }
    inline void flush(){fwrite(s,1,t-s,stdout);}
}
using output::put;
int main(){
	int n,m,i,j;
	n=rd();
	for(i=1;i<=n;i++)s[i]=rd();
	s[n+1]=1001;
	m=rd();
	for(i=n+2;i<=n+m+1;i++)s[i]=rd();
	s[n+m+2]=1001;
	suf(n+m+2);
	i=1;
	j=n+2;
	while(i<=n&&j<=n+m+1){
		if(rk[i]<rk[j]){
			put(s[i]);
			i++;
		}else{
			put(s[j]);
			j++;
		}
	}
	for(;i<=n;i++)put(s[i]);
	for(;j<=n+m+1;j++)put(s[j]);
	*(output::t)=‘\n‘;
	output::flush();
}

[BZOJ4278]Tasowanie

标签:AC   else   str   mem   output   ems   ==   etc   info   

原文地址:https://www.cnblogs.com/jefflyy/p/8504081.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!