【题解】[POI2015] KUR

题意

给你一个长度为 n01 序列,每一个数位是 0 当且仅当 (a*i+b) mod n < p 。求长度为 m01 串出现了几次。

Solution:

数论+集合求交。

首先考虑互质,所以 a*i 互不相同。如果我们枚举序列开头 x ,可以得到 m-1 个关于 a*ip 意义下的不等式,又因为 a*i%pi%p 对应,所以求出方程的解集即可。

考虑怎么解模 p 的不等式 :

0<=x+delta<=p-1 <=> -delta<=x<=p-1-delta <=> [l,r] (l<=r) 或 [0,r],[l,n-1] (l>r)

注意要把两边转成非负数,并且分类讨论。(这个当成结论记,毕竟没有严格证明)。

最后维护求交即可。

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define PII pair<ll,int>
#define All(a) a.begin(),a.end()
using namespace std;
const int mx=4e6+5;
struct node{
	int l,r;
	bool operator <(const node &a)const {
		return l<a.l||l==a.l&&r<a.r;
	}
}t[mx];
int n,a,b,p,m,tot;
char op[mx];
int main() {
	scanf("%d%d%d%d%d",&n,&a,&b,&p,&m);
	scanf("%s",op);
	//这个模数解方程很恶心 
	for(int i=0,j=0;i<m;i++) {
		int delta=(1ll*i*a+b)%n;
		int x,y;
		//结论是反的 
		if(op[i]=='1') {
			//0<=x+delta<=p-1
			//-delta<=x<=p-1-delta
			x=(-delta+n)%n;
			y=(p-1-delta+n)%n;
		}
		else {
			//p<=x+delta<=n-1
			//p-delta<=x<=n-1-delta
			x=(p-delta+n)%n;
			y=(n-1-delta+n)%n;
		}
		//分类讨论解方程
		if(x<=y) {
			t[++tot].l=x,t[tot].r=y;
		} 
		else {
			t[++tot].l=0,t[tot].r=y,t[++tot].l=x,t[tot].r=n-1;
		}
	}
	//扫一遍 (n-m,n)
	for(int i=n-m+1;i<n;i++) {
		int x=1ll*a*i%n;
		t[++tot].l=x,t[tot].r=x;
	}
	//t[] 求并集:
	//1. 先按左端点排序,然后按右端点合并
	sort(t+1,t+1+tot); 
//	for(int i=1;i<=tot;i++) {
//		printf("%d %d\n",t[i].l,t[i].r);
//	}
	int l=t[1].l,r=t[1].r,tmp=0; //细节问题
	//统计交集点的个数 
	for(int i=2;i<=tot;i++) {
		if(t[i].l<=r) r=max(r,t[i].r);
		else {
			tmp+=r-l+1;
			l=t[i].l,r=t[i].r;
		}
	}
	if(l<=r) {
		tmp+=r-l+1;
	}
	printf("%d",n-tmp);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值