欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【JZOJ A组】【NOIP2017提高A组模拟7.10】区间

程序员文章站 2022-03-31 19:09:42
...

题目

【JZOJ A组】【NOIP2017提高A组模拟7.10】区间

思路

考虑分块
把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;
}