正题
题目链接:https://www.luogu.com.cn/problem/CF346E
题目大意
给出a,n,p,ha,n,p,ha,n,p,h,在每个ax%p(x∈[0,n])ax\%p(x\in[0,n])ax%p(x∈[0,n])的位置有一个关键点,询问是否所有相邻关键点之间的距离都不超过hhh。
解题思路
没怎么写过类欧,这个题还是很坑的,需要考虑求一下hhh需要的最小值(相邻关键点直接距离的最大值)
首先第一个循环肯定都是axaxax的位置有关键点了,然后第二个循环开始是⌈pa⌉a−p+ax\lceil\frac{p}{a}\rceil a-p+ax⌈ap⌉a−p+ax,然后每个循环的起点加一个⌈pa⌉a−p\lceil\frac{p}{a}\rceil a-p⌈ap⌉a−p。好像就可以用类欧把一个大问题缩减成一个小问题了。
考虑一下细节,首先是末尾那一段,也就是a⌊pa⌋+1∼pa\lfloor\frac{p}{a}\rfloor+1\sim pa⌊ap⌋+1∼p这一段是没有用的,因为如果这一段无法到达最末尾处,那么一定存在某个kkk使得kakaka无法到达(k+1)a(k+1)a(k+1)a。
然后考虑有多少个可行的循环,简单的看是⌊anp⌋\lfloor\frac{an}{p}\rfloor⌊pan⌋,但是这样可能会有某些周期没有跑完的情况,那么后面那些间隔是没有变小的,考虑到我们求的是最大间隔,肯定是取后面的,所以此时要减一。
然后当an≤pan\leq pan≤p的时候就可以取答案了。
时间复杂度O(logn)O(\log n)O(logn)
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;
}