首页 > 其他分享 >洛谷P5309 Ynoi 2011 初始化 题解

洛谷P5309 Ynoi 2011 初始化 题解

时间:2022-11-12 22:01:41浏览次数:78  
标签:pre ch 洛谷 题解 复杂度 modify Ynoi 修改 n1

题面

我也想过根号分治,但是题目刷得少,数组不敢开,所以还是看题解做的。

这道题目要用到根号分治的思想,可以看看这道题目和我的题解。

题目要求处理一个数组a,支持如下操作。

对一个整数x,对数组长度范围内所有位置( y + x * i )加上一个数,y <= x。

查询区间和

数据范围1e5,使用分块。

处理修改

分块的一大特点就是其已经确定的单次查询复杂度,那么我们可以顺藤摸瓜,以n1/2为分界点推理操作。

对于x>=n1/2,y + x * i 对应范围内位置不超过n1/2个,可以暴力修改原数组。

对于x<n1/2,范围内的修改位置过多,但是x是小于n1/2的。

处理一个辅助数组pre[ i ][ j ]

令modify( x , y )为操作x,y,k加上的值k,那么pre[ i ][ j ]表示 modify(i , 1)+modify(i,2)+...+modify(i,j)

我们修改这个东西,单次操作时间复杂度为n1/2

这个操作在处理询问的时候有用。

处理询问

对于一段询问区间l,r。

先查询其原本的数据和x>=n1/2的修改,这部分已经经过完全修改,可以直接分块求和。

即对于整块加上整块和,散块暴力求和,时间复杂度n1/2

暴力求答案第一部分

if(lb==rb)
    for(int j=l;j<=r;j++)
        ans+=a[j],ans%=mod;
else{
    for(int j=l;j<=lb*len;j++)
        ans+=a[j],ans%=mod;
    for(int j=lb+1;j<=rb-1;j++)
        ans+=b_sum[j],ans%=mod;
    for(int j=(rb-1)*len+1;j<=r;j++)
        ans+=a[j],ans%=mod;  
}

再查询x<n1/2的修改。

这时,发现之前求了一个pre[ i ][ j ]。

对于每个y<=x,我们可以求出对应修改(x,y)在l,r内修改的次数。

 

 

如图,我们可以发现,l总处于x*k+y1,r总处于x*( k + t )-y2。

k就是(l-1)/ x,k+t就是 r / x。

我们可以先求出x在一段长为x的区间内的修改总量,即为modify(x,1)+modify(x,2)+...+modify(x,x),这东西我们之前求过,就是pre[ x ][ x ]

那么我们可以求出x在x*k~x*(k+t)内的修改总量,即为pre[ x ][ x ] * t 。

k是(l-1)/x+1,k+t是

这个修改值还需要减去modify(x,1)+modify(x,2)+...+modify(x,y1-1)和 modify(x,y2+1)+modify(x,y2+2)+...+modify(x,x)。

即pre[ x ][ y1 ]和pre[ x ][ x ]-pre[ x ][ y2 ]。

因为这些值都预处理过,所以直接调用,对一个x进行查询的时间复杂度是O(1),x一共有大约n1/2个。

这就是分块很有意思的一个地方!预处理和查询操作相互呼应,最终把单次查询时间复杂度拉到n1/2

求答案第二部分,x的修改值

for(int j=1;j<len;j++){
    lb=(l-1)/j+1,rb=(r-1)/j+1;
    if(lb==rb)
        ans-=pre[j][(l-1)%j],ans%=mod,ans+=pre[j][(r-1)%j+1],ans%=mod;
    else
        ans=(ans+1ll*(rb-lb+1)*pre[j][j]%mod-suf[j][(r-1)%j+2]-pre[j][(l-1)%j])%mod;
}

于是查这些修改值的时间是n1/2

#include<bits/stdc++.h>
using namespace std;
const int h=200010;
inline int read() {
    int s = 0, w = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9') {
        if(ch == '-') w= -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9') {
        s = s * 10 + ch - '0';
        ch = getchar();
    }
    return s * w;
}
int mod=1e9+7;
int n,m;
int a[h];
int b_sum[h];
int len;
int pre[2010][2010];
int suf[2010][2010];
int get_pos(int x){
    return (x-1)/len+1;
}
int main(){
    n=read(),m=read();
    len=120;
    for(int i=1;i<=n;i++)
        a[i]=read(),b_sum[get_pos(i)]+=a[i]%mod,b_sum[get_pos(i)]%=mod;
    int op,x,y,z;
    for(int i=1;i<=m;i++){
        op=read(),x=read(),y=read();
        if(op==1){
            z=read();
            if(x>=len)
                for(int j=y;j<=n;j+=x)
                    a[j]+=z,a[j]%=mod,b_sum[get_pos(j)]+=z,b_sum[get_pos(j)]%=mod;
            else{
                for(int j=y;j<=x;j++)
                    pre[x][j]+=z,pre[x][j]%=mod;
                for(int j=1;j<=y;j++)
                    suf[x][j]+=z,suf[x][j]%=mod;//这里的suf就是后缀和,suf[x][i]等价于pre[x][x]-pre[x][i-1]
            }                
        }
        else{
            int l=x,r=y,lb=get_pos(x),rb=get_pos(y);
            int ans=0;
            if(lb==rb)
                for(int j=l;j<=r;j++)
                    ans+=a[j],ans%=mod;
            else{
                for(int j=l;j<=lb*len;j++)
                    ans+=a[j],ans%=mod;
                for(int j=lb+1;j<=rb-1;j++)
                    ans+=b_sum[j],ans%=mod;
                for(int j=(rb-1)*len+1;j<=r;j++)
                    ans+=a[j],ans%=mod;
                
            }
            
            for(int j=1;j<len;j++){
                lb=(l-1)/j+1,rb=(r-1)/j+1;
                if(lb==rb)
                    ans-=pre[j][(l-1)%j],ans%=mod,ans+=pre[j][(r-1)%j+1],ans%=mod;
                else
                    ans=(ans+1ll*(rb-lb+1)*pre[j][j]%mod-suf[j][(r-1)%j+2]-pre[j][(l-1)%j])%mod;
            }
            printf("%d\n",(ans%mod+mod)%mod);
        }
    }
        
    return 0;
}
完整代码

总的时间复杂度是m*n1/2,理论上正确。

因为常数因子过大,无法通过本题,进一步提速请看Ynoi2011初始化卡常优化

 

标签:pre,ch,洛谷,题解,复杂度,modify,Ynoi,修改,n1
From: https://www.cnblogs.com/12103h/p/16884748.html

相关文章

  • LG3174 [HAOI2009] 毛毛虫 题解
    LG3174[HAOI2009]毛毛虫对于一棵树,我们可以将某条链和与该链相连的边抽出来,看上去就象成一个毛毛虫,点数越多,毛毛虫就越大。给定一棵树,求其最大的毛毛虫的大小。容易......
  • error in anyjson setup command: use_2to3 is invalid.问题解决
    报错errorinanyjsonsetupcommand:use_2to3isinvalid.解决因为在setuptools58之后的版本已经废弃了use_2to3pipinstallsetuptools==57.5.0......
  • 11.12 直升考 D2T2 题解
    考场上觉得人均AB,然后上午砸了,就很慌。现在还是觉得上午很砸,仍很慌。T3暴力可过??题意:给定\(n\)个格子,初始全为白色,一个人按顺序染黑一些格子,当一个格子左右的格子都被......
  • 洛谷 P4135 作诗 题解
    题面。之前做过一道很类似的题目洛谷P4168蒲公英,然后看到这题很快就想到了解法,做完这题可以对比一下,真的很像。题目要求区间内出现次数为正偶数的数字的数量。数据范......
  • 洛谷刷题_P217 [USACO1.5]回文质数 Prime Palindromes
    题目P217[USACO1.5]回文质数PrimePalindromes题目链接https://www.luogu.com.cn/problem/P1217知识点埃氏筛原理:要得到自然数n以内的全部素数,必须把不大于根号n......
  • 洛谷P4168 蒲公英 分块处理区间众数模板
    题面。许久以前我还不怎么去机房的时候,一位大佬好像一直在做这道题,他称这道题目为“大分块”。其实这道题目的思想不只可以用于处理区间众数,还可以处理很多区间数值相关......
  • [Ynoi2010] y-fast trie
    [Ynoi2010]y-fasttrie思路考虑在插入所有元素的时候对\(C\)取模。那么可以分类讨论了:\(0\leqx+y<C\)\(x+y\geqC\)考虑第二种情况等价于取集合中前两大的数,可......
  • 洛谷P7223 [RC-04] 01 背包
    [RC-04]01背包题目描述P7223[RC-04]01背包-洛谷有一个容积为正无穷的背包,你要往里面放物品。你有\(n\)个物品,第\(i\)个体积为\(a_i\)。你有一个幸运数......
  • 题解 P5188 【[COCI2009-2010#4] PALACINKE】
    postedon2022-07-2520:12:26|under题解|source做法:矩阵优化DP+容斥原理。矩阵优化DP先不要考虑商品,写个不管约束条件的DP。令\(f_{t,u}\)表示在\(t\)......
  • 题解 ABC270G【Sequence in mod P】
    postedon2022-10-2013:58:54|under题解|source有个地方写错了,改一下problemSoso有一个无穷序列\(\{X_i\}\)定义如下:\[X_i=\begin{cases}S,&(i=0)\\(A\cdo......