题目大意
给定一个长为n的数列S,对于一个给定的k,求出
表示区间[j,j + k - 1]所有元素的乘积,你只需要把所有
对P取模后,输出它们的异或和.
给定A,B,C,D,定义S的计算方法为
.
数据范围
对于20%的数据:
对于50%的数据:
另有20%的数据:
对于100%的数据:
在所有数据中均匀分布50%的数据满足P是质数,这50%中50%满足
Solutions
50%:注意
可以使用线段树维护乘积
时间复杂度:O(
->
)
另有20%:
直接暴力即可
100%:将序列分为每块长度为k的块,对于每一块维护一个前缀积和后缀积,对于每个询问利用前缀积和后缀积求出即可.
时间复杂度:O(
)
50%:
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 2e6 + 5;
struct node
{
long long val;
}tr[N << 2];
int n,k,P,A,B,C,D;
long long ans,ret;
long long S[N * 10];
void build(int rt,int l,int r)
{
if (l == r)
{
tr[rt].val = S[l];
return;
}
int mid = l + r >> 1;
build(rt << 1,l,mid);
build(rt << 1 | 1,mid + 1,r);
tr[rt].val = tr[rt << 1].val * tr[rt << 1 | 1].val % P;
}
long long query(int rt,int l,int r,int l_,int r_)
{
if (l > r_ || r < l_) return 1;
if (l_ <= l && r_ >= r) return tr[rt].val;
int mid = l + r >> 1;
return query(rt << 1,l,mid,l_,r_) * query(rt << 1 | 1,mid + 1,r,l_,r_) % P;
}
int main()
{
freopen("range.in","r",stdin);
freopen("range.out","w",stdout);
scanf("%d%d%d",&n,&k,&P);
scanf("%d%d%d%d",&A,&B,&C,&D);
S[1] = A;
for (int i = 2 ; i <= n ; i++)
{
long long p = S[i - 1] * B;
if (p) p = p % D + C; else p = C;
if (p) S[i] = p % D; else S[i] = 0;
}
if (n - k <= 10)
{
for (int i = 1,j = k ; i <= n - k + 1 ; i++,j++)
{
ret = 1;
for (int l = i ; l <= j ; l++) ret = ret * S[l] % P;
ans = ans ^ ret;
}
if (ans) ans = ans % P;
printf("%lld\n",ans);
return 0;
}
build(1,1,n);
for (int i = 1,j = k ; i <= n - k + 1 ; i++,j++)
{
long long t = query(1,1,n,i,j);
if (t) t = t % P;
ans ^= t;
}
if (ans) ans = ans % P;
printf("%lld\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
100%:
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 2e7 + 5;
int n,k,P,tot,A,B,C,D;
int pre[N],suf[N],S[N];
long long ret,ans;
int main()
{
freopen("range.in","r",stdin);
freopen("range.out","w",stdout);
scanf("%d%d%d",&n,&k,&P);
scanf("%d%d%d%d",&A,&B,&C,&D);
S[1] = A;
for (int i = 2 ; i <= n ; i++)
{
ret = (S[i - 1] * 1LL * B + C) % D;
S[i] = ret;
}
for (int w = 1 ; w <= n ; w += k)
{
pre[w] = S[w];
for (int j = w + 1 ; j <= min(w + k - 1,n) ; j++)
{
ret = pre[j - 1] * 1LL * S[j] % P;
pre[j] = ret;
}
suf[min(w + k - 1,n)] = S[min(w + k - 1,n)];
for (int j = min(w + k - 1,n) - 1 ; j >= w ; j--)
{
ret = suf[j + 1] * 1LL * S[j] % P;
suf[j] = ret;
}
}
for (int i = 1 ; i <= n - k + 1 ; i++)
{
if (pre[i] == S[i]) ret = suf[i] % P;
else ret = suf[i] * 1LL * pre[i + k - 1] % P;
ans ^= ret;
}
printf("%lld\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}