卧薪尝胆,厚积薄发。
POI2015 KUR
Date: Mon Oct 29 19:33:23 CST 2018
In Category:
NoCategory
Description:
给定
$n,a,b,p$
,其中
$n,a$
互质。定义一个长度为
$n$
的01串
$c[0\dots n)$
,其中
$c[i]=0$
当且仅当
$(a\times i+b) \mod n < p$
。给定一个长为
$m$
的小
$01$
串,求出小串在大串中出现了几次。
$1\leqslant n\leqslant 10^9,1\leqslant m\leqslant 10^6$
Solution:
$n,a$
互质告诉我们
$(a\times i+b)\mod n$
是两两不同的,也就是说我们可以通过
$f(i)=(a\times i+b)\mod n$
来代表每个
$i$
,要想从
$p$
开始
$m$
和原串能匹配,
$0$
的位置要满足
$0\leqslant (f(p)+a\times p')\%n<p$
,其他位置满足
$p\leqslant (f(p)+a\times p')\% n<n$
,移个项会发现是一个关于
$f(p)$
的模意义下的不等式,注意有些
$l>r$
的情况要分裂成两部分,最后把所有区间做区间交即可,但区间交不是很好做,转化为补集的区间补再用
$n$
减即可。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
int n,a,b,p,m;
#define MAXM 1000010
int v[MAXM];
inline int getc()
{
register char c = getchar();
while(c != '0' && c != '1')c = getchar();
return c - '0';
}
struct seg
{
int l,r;
}s[MAXM * 3];
bool cmp_r(seg a,seg b){return a.l < b.l;}
int cnt = 0;
int main()
{
scanf("%d%d%d%d%d",&n,&a,&b,&p,&m);
for(int i = 1;i <= m;++i)v[i] = getc();
for(int i = 1;i <= m;++i)
{
int l,r;
if(v[i])
{
l = (0 - (1ll * a * (i - 1) % n) + n) % n;
r = (p - (1ll * a * (i - 1) % n) + n - 1) % n;
}
else
{
l = (p - (1ll * a * (i - 1) % n) + n) % n;
r = (n - (1ll * a * (i - 1) % n) + n - 1) % n;
}
if(l <= r)
{
++cnt;s[cnt].l = l;s[cnt].r = r;
}
else
{
++cnt;s[cnt].l = 0;s[cnt].r = r;
++cnt;s[cnt].l = l;s[cnt].r = n - 1;
}
}
for(int i = n - m + 1;i < n;++i)
{
++cnt;
s[cnt].l = (1ll * a * i + b) % n;
s[cnt].r = (1ll * a * i + b) % n;
}
sort(s + 1,s + 1 + cnt,cmp_r);
int cur = -1,ans = 0;
for(int i = 1;i <= cnt;++i)
{
if(s[i].l > cur)
{
ans += s[i].l - cur - 1;
}
cur = max(cur,s[i].r);
}
ans += n - 1 - cur;
cout << ans << endl;
return 0;
}
In tag:
数学-模运算
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡