P5309 [Ynoi2011] 初始化 题解?

前言

  • 好难理解。。。

\(solve\)

  • 首先我们直接打暴力,就是朴素分块,获得 \(40pts\) 跑路
点击查看代码
void Upd(int x,int y,int z)
{
    for (int i=y;i<=n;i+=x)
        (a[i]+=z)%=p,(s[pos[i]]+=z)%=p;
}
int que(int l,int r)
{
    int res=0;
    if (pos[l] == pos[r])
        for (int i=l;i<=r;i++)
            (res+=a[i])%=p;
    else
    {
        for (int i=l;i<=R[pos[l]];i++)
            (res+=a[i])%=p;
        for (int i=L[pos[r]];i<=r;i++)
            (res+=a[i])%=p;
        for (int i=pos[l]+1;i<pos[r];i++)
            (res+=s[i])%=p;
    }
    return res;
}
  • 暴力还挺快的欸
  • 我们发现数据中限定 \(x\) 巨大的 \(Subtask\) 通过了,这启发我们在 \(x\) 的值域下手,考虑根号分治
  • 对于 \(x\) 大于阈值 \(T\) 的,直接暴力跳,用分块维护,和上面说的暴力一样
  • 然后对于 \(x\) 小于等于阈值的,我们要换一个方法了,开始观察题目

  • \(Waring!\)
  • 以下内容是msjing的理解,可能不对,有锅请指正谢谢喵

  • 发现 \(y \le x\),并且发现修改呈现周期性,是一个一个跳 \(x\) 的,所以我们对于每个 \(x\),统计每个点的修改操作和,但是这样跳太慢,所以进行前后缀操作
  • 我们对于区间 \([1,x]\),记录前后缀,以 \(y\) 为分界,我们可以理解为这样操作将序列划分为了多个长 \(x\) 的段,我们维护的前后缀数组可以很方便的维护整块(指询问区间完全包含这个长 \(x\) 的区间)和散块
  • 查询时,当一个长 \(x\) 区间包含了询问的左右端点,直接用前缀做差求,否则整块直接算,散块由于有前缀和后缀,也可以很快得到
  • 然后就是经典常谈的卡常了
  • 别挂 #define int long long,实测会慢 \(500ms\),别老是取模,取模巨慢

\(code\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
constexpr int maxn=2e5+10,maxm=450,p=1e9+7;
struct IO
{
	static const int Size=(1<<16);
	char buf[Size],*p1,*p2;
	int st[105],Top;
	~IO(){clear();}
	inline void clear(){fwrite(buf,1,Top,stdout);Top=0;}
	inline char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,Size,stdin),p1==p2)?EOF:*p1++;}
	inline void pc(const char c){Top==Size&&(clear(),0);buf[Top++]=c;}
	inline IO& operator >>(char& c){while(c=gc(),c==' ' || c=='\n' || c=='\r');return *this;}
	template<typename T>inline IO& operator >>(T& x)
    {
		x=0;bool f=0;char c=gc();
		while(!isdigit(c)){if(c=='-') f=1;c=gc();}
		while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
		f?x=-x:0;
		return *this;
	}
	inline IO& operator >>(string& s)
    {
		s="";char c=gc();
		while(c==' ' || c=='\n' || c=='\r') c=gc();
		while(c!=' ' && c!='\n' && c!='\r' && c!=EOF) s+=c,c=gc();
		return *this;
	}
	inline IO& operator <<(const char c){pc(c);return *this;}
	template<typename T> inline IO& operator <<(T x)
    {
		if(x<0) pc('-'),x=-x;
		do st[++st[0]]=x%10,x/=10;while(x);
		while(st[0]) pc(st[st[0]--]+'0');
		return *this;
	}
	inline IO& operator <<(const string s){for(auto c:s) pc(c);return *this;}
	inline IO& operator <<(const char* c){for(int i=0;c[i];i++) pc(c[i]);return *this;}
} fin,fout;
int n,m;
int a[maxn];
int L[maxn],R[maxn],pos[maxn],cnt;
long long s[maxn];
long long pr[maxm][maxm],nt[maxm][maxm];
void Upd(int x,int y,int z)
{
    if (x>cnt)
        for (int i=y;i<=n;i+=x)
            (a[i]+=z)%=p,(s[pos[i]]+=z)%=p;
    else
    {
        for (int i=y;i<=x;i++)
            (pr[x][i]        +=z)%=p;
        for (int i=y;i>=1;i--)
            (nt[x][i]+=z)%=p;
    }
}
long long que(int l,int r)
{
    long long res=0;
    if (pos[l] == pos[r])
        for (int i=l;i<=r;i++)
            (res+=a[i])%=p;
    else
    {
        for (int i=l;i<=R[pos[l]];i++)
            (res+=a[i])%=p;
        for (int i=L[pos[r]];i<=r;i++)
            (res+=a[i])%=p;
        for (int i=pos[l]+1;i<pos[r];i++)
            (res+=s[i])%=p;
    }
    for (int i=1;i<=cnt;i++)
    {
        int bl=(l-1)/i+1,br=(r-1)/i+1;
        if (bl == br)
            (res+=pr[i][(r-1)%i+1]-pr[i][(l-1)%i])%=p;
        else
            (res+=(br-bl-1)*pr[i][i]+pr[i][(r-1)%i+1]+nt[i][(l-1)%i+1])%=p;
    }
    return res;
}
signed main()
{
    fin >> n >> m;
    for (int i=1;i<=n;i++) fin >> a[i];
    cnt=sqrt(n);
    for (int i=1;i<=cnt;i++)
        L[i]=R[i-1]+1,R[i]=cnt*i;
    if (R[cnt]<n)
        cnt++,L[cnt]=R[cnt-1]+1,R[cnt]=n;
    for (int i=1;i<=n;i++)
        for (int j=L[i];j<=R[i];j++)
            pos[j]=i,(s[i]+=a[j])%=p;
    for (int i=1;i<=m;i++)
    {
        int op;
        fin >> op;
        if (op == 1)
        {
            int x,y,z;
            fin >> x >> y >> z;
            Upd(x,y,z);
        }
        else
        {
            int l,r;
            fin >> l >> r;
            fout << (que(l,r)+p)%p << '\n';
        }
    }
    return 0;
}

后话

  • lxl怎么出出来这种牛子题的虽然不是lxl出的,看一晚上题解都没全看懂
posted @ 2026-08-26 22:00  msjing  阅读(5)  评论(0)    收藏  举报