洛谷P5425 [USACO19OPEN]I Would Walk 500 Miles G
题目
https://www.luogu.com.cn/problem/P5425
思路
又是喜闻乐见的二分答案题,那么关键就是check函数的编写了。
我们考虑每次枚举一个\(mid\),然后判断是否存在一种分配方案使所有不同组奶牛之间的距离都\(\geq mid\)
对于这个距离\((2019201913x+2019201949y) \mod 2019201997\),根据同余性质,直接变成\(-84*x-48*y\),又:\(N\leq 7500\),所以距离很小,之后这个取模就没用了。
同时,根据式子,发现x和y越大,不满足条件的可能性就越大。
对于\(n\)号奶牛,我们看哪些可以和它分到不同组,哪些必须和它分到同一组。根据式子单调性可以发现,必须和它分到同一组的奶牛必然是\(n-1,n-2,...,n-t\)这样连续的一段。
同时,既然\(n-t-1\)号可以和\(n\)号分开,那它也必然可以和\(n-1,n-2,...n-t\)号分开,所以处理完\(n\)号就直接去处理\(n-t-1\)号,每头奶牛只访问一次,所以check函数是O(n)的。
总体时间复杂度为\(nlog2019201997\),可以承受。
代码
#include<cstdio>
#include<cstdlib>
#define mod 2019201997
#define ll long long
using namespace std;
int n,m;
ll f(int x,int y){
return -84*x-48*y;
}
int check(ll x){
int i=n,cnt=0,j=1;
while(i>=1){
j=i-1;
while(j>=1&&f(j,i)<x){
j--;
}
cnt++;
i=j;
}
if(cnt>=m) return 1;
else return 0;
}
int main(){
int i,j;
ll l=-mod,r=-1;
scanf("%d%d",&n,&m);
while(l<r){
ll mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid-1;
}
printf("%lld",mod+l);
// system("pause");
return 0;
}