链接
https://nanti.jisuanke.com/t/28871
分块
原来分块还能这么用!真是神了
看到
∑n≤107
∑
n
≤
10
7
我觉得自己就不可能想到分块上去了
这题其实是分治的思路
在线段树上的时候我们经常会把一个区间劈成两半,分别是两个区间的前缀和后缀
这个题也是考虑分治,它肯定覆盖了某些块,两端是一些块的前缀或者后缀,那么就预处理一下每个块的前缀积和后缀积,每次
O(1)
O
(
1
)
就行了
中国剩余定理
这题 ∑N≤107 ∑ N ≤ 10 7 ,单次 N≤106 N ≤ 10 6 , CRT C R T 有风险,如果遇到那种 P=2×3×5..... P = 2 × 3 × 5..... 那种的话,复杂度也是很高的,代码暂时先不想写了
代码
//分块
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <cmath>
#define maxn 1010000
#define cl(x,y) memset(x,y,sizeof(x))
#define inf 0x3f3f3f3f
#define ll long long
#define maxb 1010
using namespace std;
ll a[maxn], S[maxb][maxb], s1[maxb][maxb], s2[maxb][maxb], s[maxb], N, M, P, X, Y, Z, B;
void init()
{
ll i, j;
scanf("%lld%lld%lld%lld%lld%lld",&M,&P,a+1,&X,&Y,&Z);
B=sqrt(N);
for(i=2;i<=N;i++)a[i]=(X*a[i-1]%P*a[i-1]+Y*a[i-1]+Z)%P;
for(i=0;i<=N/B;i++)
{
for(j=0;j<B;j++)s1[i][j]=(j?s1[i][j-1]:1)*a[i*B+j]%P;
for(j=B-1;j>=0;j--)s2[i][j]=(j==B-1?1:s2[i][j+1])*a[i*B+j]%P;
s[i]=s1[i][B-1];
}
for(i=1;i<N/B;i++)
{
S[i][i]=s[i];
for(j=i+1;j<N/B;j++)S[i][j]=S[i][j-1]*s[j]%P;
}
}
ll calc(ll l, ll r)
{
ll i, pdt=1;
if(l/B<r/B-1)pdt=S[l/B+1][r/B-1];
if(l/B<r/B)pdt=pdt*s2[l/B][l%B]%P*s1[r/B][r%B]%P;
else for(int i=l;i<=r;i++)pdt=pdt*a[i]%P;
return pdt;
}
void work()
{
ll i, ans=0;
for(i=1;i+M-1<=N;i++)ans+=calc(i,i+M-1);
printf("%lld\n",ans);
}
int main()
{
while(~scanf("%lld",&N))init(), work();
return 0;
}