最近刚讲了最短路,说要考试我以为是考最短路,然而只有一道是最短路...
数据似乎有一点问题,不管了,反正手工测评都是对的,那现在就来看看题吧。
Balanced:(此处并没有网址)
题意概述:$n$ $(n<=50,000)$头牛排成一排,给定每头牛的位置,有两种种族,选出一个尽量长的区间使得这个区间内两种牛的数量相等。
首先可以想到枚举...前缀和...然而还是$O(N^2)$的复杂度,很显然是过不了的。思考一下前缀和的做法,用两个数组分别表示两种牛数量的前缀和。当$a[j]-a[i-1]=b[j]-b[i-1]$时,$x[j]-x[i]$就是一个合法的答案了。那对这个式子进行移项:$a[j]-b[j]=a[i-1]-b[i-1]$,所以可以再开一个数组表示$x[i]=a[i]-b[i]$,如果两个位置的$x$相同,就是一个合法的答案,而且区间越长答案一定更优,所以只需要保存每个$x$出现的第一次和最后一次位置,统计答案时取max就可以了。注意$x$数组可以出现负数,所以将整个数组同时加上$n$就可以避免负数了。
1 // shzr 2 3 # include <cstdio> 4 # include <iostream> 5 # include <algorithm> 6 # include <cstring> 7 8 using namespace std; 9 10 const int maxn=50009; 11 int n,s1[maxn],s2[maxn],ans,x[maxn],minn[maxn*3],maxx[maxn*3]; 12 struct co 13 { 14 int id,x; 15 }a[maxn]; 16 bool cmp(co a,co b) 17 { 18 return a.x<b.x; 19 } 20 21 int main() 22 { 23 scanf("%d",&n); 24 memset(minn,127,sizeof(minn)); 25 for (int i=1;i<=n;++i) 26 scanf("%d%d",&a[i].id,&a[i].x); 27 sort(a+1,a+1+n,cmp); 28 minn[0]=0; 29 for (int i=1;i<=n;++i) 30 { 31 if(a[i].id==0) s1[i]++; 32 if(a[i].id==1) s2[i]++; 33 s1[i]+=s1[i-1]; 34 s2[i]+=s2[i-1]; 35 x[i]=s1[i]-s2[i]; 36 minn[ x[i]+n+2 ]=min(minn[ x[i]+n+2 ],i); 37 maxx[ x[i]+n+2 ]=max(maxx[ x[i]+n+2 ],i); 38 } 39 for (int i=0;i<=2*n+2;++i) 40 { 41 if(maxx[i]==0||minn[i]>n) continue; 42 if(maxx[i]==minn[i]) continue; 43 ans=max(ans,a[ maxx[i] ].x-a[ minn[i]+1 ].x); 44 } 45 printf("%d",ans); 46 return 0; 47 }