CF346E-Doodle Jump【类欧】

正题

题目链接:https://www.luogu.com.cn/problem/CF346E


题目大意

给出(a,n,p,h),在每个(ax\%p(xin[0,n]))的位置有一个关键点,询问是否所有相邻关键点之间的距离都不超过(h)


解题思路

没怎么写过类欧,这个题还是很坑的,需要考虑求一下(h)需要的最小值(相邻关键点直接距离的最大值)

首先第一个循环肯定都是(ax)的位置有关键点了,然后第二个循环开始是(lceilfrac{p}{a} ceil a-p+ax),然后每个循环的起点加一个(lceilfrac{p}{a} ceil a-p)。好像就可以用类欧把一个大问题缩减成一个小问题了。

考虑一下细节,首先是末尾那一段,也就是(alfloorfrac{p}{a} floor+1sim p)这一段是没有用的,因为如果这一段无法到达最末尾处,那么一定存在某个(k)使得(ka)无法到达((k+1)a)

然后考虑有多少个可行的循环,简单的看是(lfloorfrac{an}{p} floor),但是这样可能会有某些周期没有跑完的情况,那么后面那些间隔是没有变小的,考虑到我们求的是最大间隔,肯定是取后面的,所以此时要减一。

然后当(anleq p)的时候就可以取答案了。

时间复杂度(O(log n))


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
ll a,n,p,h,T;
ll solve(ll a,ll n,ll p){
    if(a*n<p)return max(a,p-a*n);
    ll z=a*n/p;
    if(a*n%p<p/a*a-a)z--;
    return solve((p+a-1)/a*a-p,z,a);
}
signed main()
{
    scanf("%lld",&T);
    while(T--){
        scanf("%lld%lld%lld%lld",&a,&n,&p,&h);
        a%=p;
        if(a<=h){puts("YES");continue;}
        if(a*n<=p){puts(h>=a?"YES":"NO");continue;}
        puts((solve(a,n,p)<=h)?"YES":"NO");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/QuantAsk/p/14315053.html