LOJ #3144 [APIO2019]奇怪装置 数学推导+线段合并qwq

题目链接:传送门

取两个不相等的整数 a , b a,b a,b,考虑什么情况下它们的 ( x , y ) (x,y) (x,y)相同:
( a + ⌊ a B ⌋ ) m o d A = ( b + ⌊ b B ⌋ ) m o d A (a+\lfloor\frac{a}{B}\rfloor)mod A=(b+\lfloor\frac{b}{B}\rfloor) modA (a+Ba)modA=(b+Bb)modA
a a a m o d mod mod B = b B=b B=b m o d mod mod B B B
a = k B + b a=kB+b a=kB+b,代入式子,大莉化简一波,发现:
a a a m o d mod mod A B g c d ( A , B + 1 ) = b \frac{AB}{gcd(A,B+1)} = b gcd(A,B+1)AB=b m o d mod mod A B g c d ( A , B + 1 ) \frac{AB}{gcd(A,B+1)} gcd(A,B+1)AB
所以 A B g c d ( A , B + 1 ) \frac{AB}{gcd(A,B+1)} gcd(A,B+1)AB是一个周期。
于是问题转化为在 [ 0 , A B g c d ( A , B + 1 ) ) [0,\frac{AB}{gcd(A,B+1)}) [0,gcd(A,B+1)AB)区间内的 n n n条线段的交集大小。
按左端点排序一波,大莉 O ( n ) O(n) O(n)求交集大小即可qwq。
要注意 A B g c d ( A , B + 1 ) \frac{AB}{gcd(A,B+1)} gcd(A,B+1)AB过大时,把它设成 2 ∗ 1 0 18 2*10^{18} 21018即可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;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值