版权声明:欢迎随便转载。 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;
}