FZU 2267-贪心+(hash or 后缀数组)

版权声明:欢迎随便转载。 https://blog.csdn.net/a1214034447/article/details/89470649

题目链接:https://vjudge.net/problem/FZU-2267

解题思路:

很明显只有当两个数相等的时候才决定谁要先选,一个很明显的贪心策略就是以这个数为开头到结尾,那个数大就选哪个数的开头。比如 3 7 6和3 7 5,肯定是选第一个的3,因为376>375。

那么接下来就是考虑比大小的问题,一个方法就是把两个串拼接起来然后做后缀数组,那个排名大取哪个。

另一种我们则可以去二分最长公共前缀长度,然后去比较最长前缀长度之后的那个数肯定就可以比较出大小了,至于公共前缀,我们则可以取hash。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define inf 0x3f3f3f3f
#define fi first
#define se second
#define inf 0x3f3f3f3f
using namespace std;
typedef unsigned long long ull; 
const int mx = 1e5 + 10;
const ull base = 123;
ull pws[mx],va[mx],vb[mx];
int a[mx],b[mx];
int main(){
	int t,ca = 1;scanf("%d",&t);
	pws[0] = 1;for(int i=1;i<mx;i++) pws[i] = base*pws[i-1];
	while(t--){
		int lena,lenb;
		scanf("%d%d",&lena,&lenb);
		a[lena+1] = b[lenb+1] = -1;
		for(int i=1;i<=lena;i++) scanf("%d",a+i);
		for(int i=1;i<=lenb;i++) scanf("%d",b+i);
		for(int i=1;i<=lena;i++){
			va[i] = va[i-1]*base + a[i];
		}
		for(int i=1;i<=lenb;i++){
			vb[i] = vb[i-1]*base + b[i];
		}
		printf("Case %d: ",ca++);
		int l = 1,r = 1;
		while(l<=lena||r<=lenb){
			if(a[l]>b[r]) putchar(a[l]+'0'),l++;
			else if(a[l]<b[r]) putchar(b[r]+'0'),r++;
			else{
				putchar(b[r]+'0');
				int L = 1,R = min(lena-l+1,lenb-r+1);
				ull c,d;
				while(L<R){
					int mid = (L+R+1)>>1;
					c = va[l+mid-1] - va[l-1]*pws[mid];
					d = vb[r+mid-1] - vb[r-1]*pws[mid];
					if(c==d) L = mid;
					else R = mid - 1;
				}
				if(b[r+L]>a[l+L]) r++;
				else l++; 
			}
		}
		puts("");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/a1214034447/article/details/89470649