2018 ACM-ICPC 江苏站 G.WIndow

链接

https://nanti.jisuanke.com/t/28871

分块

原来分块还能这么用!真是神了
看到 n107 ∑ n ≤ 10 7 我觉得自己就不可能想到分块上去了
这题其实是分治的思路
在线段树上的时候我们经常会把一个区间劈成两半,分别是两个区间的前缀和后缀
这个题也是考虑分治,它肯定覆盖了某些块,两端是一些块的前缀或者后缀,那么就预处理一下每个块的前缀积和后缀积,每次 O(1) O ( 1 ) 就行了

中国剩余定理

这题 N107 ∑ N ≤ 10 7 ,单次 N106 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值