【JZOJ A组】【NOIP2017提高A组模拟7.10】区间
程序员文章站
2022-03-31 19:09:42
...
题目
思路
考虑分块
把n个序列分成长度为k的若干段,当然最后一段不一定是k。
然后对每一块求一个前缀、后缀乘积和。
最后暴枚区间,注意到每个区间刚好会被两段或一段覆盖,直接O(1)算即可。
代码
#include<cstdio>
using namespace std;
typedef long long ll;
const int N=2e7+1;
int n,k,mod,b,c,d,ans;
int s[N],pre[N],suf[N];
int main()
{
freopen("range.in","r",stdin); freopen("range.out","w",stdout);
scanf("%d%d%d",&n,&k,&mod);
scanf("%d%d%d%d",&s[1],&b,&c,&d);
for(int i=2; i<=n; i++) s[i]=(s[i-1]*1ll*b+c)%d;
int num=n/k;
for(int i=0; i<num; i++)
{
int t=i*k+1;
pre[t]=s[t];
for(int j=t+1; j<t+k; j++) pre[j]=pre[j-1]*1ll*s[j]%mod;
suf[t+k-1]=s[t+k-1];
for(int j=t+k-2; j>=t; j--) suf[j]=suf[j+1]*1ll*s[j]%mod;
}
if(n%k)
{
int t=num*k+1;
pre[t]=s[t];
for(int i=t+1; i<=n; i++) pre[i]=pre[i-1]*1ll*s[i]%mod;
suf[n]=s[n];
for(int i=n-1; i>=t; i--) suf[i]=suf[i+1]*1ll*s[i]%mod;
}
for(int i=1; i<=n-k+1; i++)
if(i%k==1) ans^=pre[i+k-1]; else
ans^=suf[i]*1ll*pre[i+k-1]%mod;
printf("%d",ans);
return 0;
}
上一篇: 安眠药的副作用,为防依赖成瘾记四点
推荐阅读
-
JZOJ5397. 【NOIP2017提高A组模拟10.6】Biology
-
JZOJ6893. 【提高组模拟】小 T 与灵石(stone)题解
-
JZOJ 5820. 【NOIP提高A组模拟2018.8.16】 非法输入
-
JZOJ5822 【NOIP提高A组模拟2018.8.16】 量子纠缠
-
JZOJ 5395. 【NOIP2017提高A组模拟10.6】Count
-
100043. 【NOIP2017提高A组模拟7.13】第K小数
-
JZOJ6893. 【提高组模拟】小 T 与灵石(stone)题解
-
【JZOJ A组】【NOIP2017提高A组模拟7.10】随机
-
【JZOJ A组】【NOIP2017提高A组模拟7.10】区间
-
【jzoj5285】【NOIP提高组模拟赛A组8.16】【排序】