LOJ #3144 [APIO2019]奇怪裝置 數學推導+線段合併qwq

題目鏈接:傳送門

取兩個不相等的整數a,ba,b,考慮什麼情況下它們的(x,y)(x,y)相同:
(a+aB)modA=(b+bB)modA(a+\lfloor\frac{a}{B}\rfloor)mod A=(b+\lfloor\frac{b}{B}\rfloor) modA
aa modmod B=bB=b modmod BB
a=kB+ba=kB+b,代入式子,大莉化簡一波,發現:
aa modmod ABgcd(A,B+1)=b\frac{AB}{gcd(A,B+1)} = b modmod ABgcd(A,B+1)\frac{AB}{gcd(A,B+1)}
所以ABgcd(A,B+1)\frac{AB}{gcd(A,B+1)}是一個週期。
於是問題轉化爲在[0,ABgcd(A,B+1))[0,\frac{AB}{gcd(A,B+1)})區間內的nn條線段的交集大小。
按左端點排序一波,大莉O(n)O(n)求交集大小即可qwq。
要注意ABgcd(A,B+1)\frac{AB}{gcd(A,B+1)}過大時,把它設成210182*10^{18}即可qwq。

代碼

#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
#define rl register ll
using namespace std;
typedef long long ll;
ll read() {
	rl x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9') {
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9') {
		x=10*x+ch-'0';
		ch=getchar();
	}
	return x*f;
}
inline char GetChar() {
	char ch=getchar();
	while(ch!='t' && ch!='q')	ch=getchar();
	return ch;
}
const int Size=2000005;
ll n,A,B;
struct Segment {
	ll l,r;
} w[Size];
inline bool comp(Segment x,Segment y) {
	if(x.l!=y.l)	return x.l<y.l;
	return x.r<y.r;
}
int main() {
	n=read();
	A=read();
	B=read();
	ll len=A/__gcd(A,B+1);
	if(2e18/B>=len) {
		len=len*B;
	} else {
		len=2e18;
	}
	int tot=0;
	for(re i=1; i<=n; i++) {
		ll l=read();
		ll r=read();
		ll tmp=r/len-l/len;
		if(tmp>1) {
			printf("%lld",len);
			return 0;
		} else if(tmp==1) {
			w[++tot].l=l%len; w[tot].r=len-1;
			w[++tot].l=0;	w[tot].r=r%len;
		} else {
			w[++tot].l=l%len;
			w[tot].r=r%len;
		}
	}
	sort(w+1,w+1+tot,comp);
	ll maxr=-1,ans=0;
	for(re i=1; i<=tot; i++) {
		if(w[i].l<=maxr) {
			if(w[i].r<=maxr)	continue;
			ans+=w[i].r-maxr;
			maxr=w[i].r;
		} else {
			ans+=w[i].r-w[i].l+1;
			maxr=w[i].r;
		}
	}
	printf("%lld",ans);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章