【洛谷P3409】值日班长值周班长

题目

题目链接:https://www.luogu.com.cn/problem/P3409
一开始读题了,一下所有 \(m\)\(p\) 与题目中意思对调。
话说,在一个学期共有 \(n\) 个值日班长,其中 A 是第 \(p\) 个值日班长,共有 \(m\) 个值周班长,B 是第 \(q\) 个值周班长。假设不考虑假期及其他额外上课休假,以及重排值日班长值周班长,即永远每周上 5 天休息 2 天,且这个学期永远不会结束。请问这学期第几天会第一次遇上 A 是值日班长且 B 是值周班长,若永远不会输出 Orz mgh!!!。
\(n,m\leq 10^9\)

思路

被卡了 long long 调了好久最后看题解都是用了 int128 的。。。
考虑设值日班长轮了 \(x\) 轮,值周班长轮了 \(y\) 轮,显然就是要求最小的非负整数解 \(x,y\) 满足:

\[nx+p=5(my+q)+k \]

其中 \(k\) 是这周还有多少天结束,显然可以枚举。
对于每一个枚举的 \(k\),直接把式子化成

\[nx-5my=5q+k-p \]

直接解出 \(x,y\) 的最小非负整数解,答案即为 \(nx+p\)
时间复杂度 \(O(T\log n)\)

代码

#include <bits/stdc++.h>
using namespace std;
typedef __int128 ll;

const ll Inf=9223372036854775807LL;
ll ans,n,m,p,q;
long long _,__,___,____;
/*
ll read()
{
	ll d=0; char ch=getchar();
	while (!isdiigt(ch)) ch=getchar();
	while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
	return d;
}
*/
void write(ll x)
{
	if (x>9) write(x/10);
	putchar(x%10+48);
}

ll exgcd(ll a,ll b,ll &x,ll &y)
{
	if (!b) { x=1; y=0; return a; }
	ll d=exgcd(b,a%b,x,y),t=x; x=y; y=t-a/b*y;
	return d;
}

int main()
{
	while (scanf("%lld%lld%lld%lld",&_,&__,&___,&____)!=EOF)
	{
		n=_; p=__; m=___; q=____;  // 疯了
		p--; q--; ans=-1;
		for (ll k=0;k<=4;k++)
		{
			ll x,y,d=exgcd(n,5*m,x,y),l=(n*5*m)/d/n;
			if ((5*q+k-p)%d) continue;
			x=((5*q+k-p)/d*x%l+l)%l;
			if (ans<0) ans=x*n+p+1;
				else ans=min(ans,x*n+p+1);
		}
		if (ans>=0) write(ans);
			else printf("Orz mgh!!!");
		putchar(10);
	}
	return 0;
}
posted @ 2021-03-05 15:11  stoorz  阅读(108)  评论(0)    收藏  举报