BZOJ4377: [POI2015]Kurs szybkiego czytania

111 篇文章 0 订阅
14 篇文章 0 订阅

题目大意:给定n,a,b,p,其中n,a互质。定义一个长度为n的01串c[0..n-1],其中c[i]==0当且仅当(ai+b) mod n < p。
                  给定一个长为m的小01串,求出小串在大串中出现了几次。


首先很容易想到,当确定小串的第一位在大串当中的位置时,小串中所有数的值就都确定了

先不考虑0和1

不妨设x为小串第一个数实际的值

则我们可以知道小串第i个数实际的值为(x+(i-1)a)%p

所以我们可以根据小串实际的值是0还是1,列出化简后形如x1≤x%p≤x2的m个不等式

然后怎么解呢?

我们可以把不等式转化为x不能取的值的一些区间

然后把这些区间放在一起取个并,最后没被覆盖的就是可以取的了!

然后我们就可以知道小串首位都可以是哪些值了

把这个再刨去大串中最后那m-1个不能作为小串开头的数,就是最后的答案了

(至于上面这一步,也可以把他们当成m-1个区间扔进去一起算区间并)


#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 3000010
using namespace std;
long long n,m,p,a,b,cnt;
char c[N];
struct ppp {long long s,e;}l[2*N];
bool cmp(ppp x,ppp y) {return x.s<y.s;}
int main()
{
	scanf("%lld%lld%lld%lld%lld",&n,&a,&b,&p,&m);
	long long i,j,k,x,y;
	scanf("%s",c+1);
	for(i=1;i<=m;i++)
	{
		if(c[i]=='0')
		{
			x=((p-(i-1)*a)%n+n)%n;
			y=((n-1-(i-1)*a)%n+n)%n;
		}
		else
		{
			x=((0-(i-1)*a)%n+n)%n;
			y=((p-1-(i-1)*a)%n+n)%n;
		}
		if(x>y)
		{
			cnt++;l[cnt].s=x;l[cnt].e=n-1;
			cnt++;l[cnt].s=0;l[cnt].e=y;
		}
		else
		{
			cnt++;l[cnt].s=x;l[cnt].e=y;
		}
	}
	for(i=n-m+1;i<n;i++)
	{
		cnt++;
		l[cnt].s=(a*i+b)%n;
		l[cnt].e=(a*i+b)%n;
	}
	sort(l+1,l+cnt+1,cmp);
	long long maxn=-1;
	long long ans=0;
	for(i=1;i<=cnt;i++)
	{
		if(l[i].s>maxn)
		ans+=l[i].s-maxn-1;
		maxn=max(l[i].e,maxn);
	}
	printf("%lld",ans+(n-1-maxn));
}

时间复杂度是算区间并的复杂度O(MlogM)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值