题解:SP7299 MULTQ3 - Multiples of 3
Pro
完成两种操作:
- 区间加 。
- 区间有多少个倍数为 的倍数。
Sol
Subtask 1
考虑每次循环 ,时间复杂度 。
Subtask 2
因为 可过,所以考虑分块。
Update
定义 表示第 块中对 取模等于 的数的个数。
对于散块维护 ;
对于整块,因为每次加 ,原来模 等于 的数,会变成模 。即:。
注意还有个区间加,带一个 就行。
Query
对于散块直接计算。
对于整块,直接取 。
时间复杂度
分块时间复杂度 。
Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
int id[100005],ll[350],n,tot=0;
int a[100005],lzy[350];
int mod[3][350];
void build()
{
int kc=sqrt(n);
for(int i=1;i<=n;i++)
{
id[i]=(i-1)/kc+1;
if(id[i]!=id[i-1]) ll[++tot]=i;
mod[0][tot]++;
}
ll[tot+1]=n+1;
}
int query_sk(int l,int r)
{
int ans=0;
for(int i=l;i<=r;i++) ans+=((a[i]+lzy[id[l]])%3==0);
return ans;
}
int query_zk(int k){return mod[0][k];}
void update_sk(int l,int r,int k)
{
for(int i=0;i<3;i++) mod[i][k]=0;
for(int i=l;i<=r;i++) a[i]++;
for(int i=ll[k];i<ll[k+1];i++)
mod[(a[i]+lzy[k])%3][k]++;
}
void update_zk(int k) // 0 1 2
{
lzy[k]++;
swap(mod[0][k],mod[1][k]); // 1 0 2
swap(mod[0][k],mod[2][k]); // 2 0 1
}
int query(int l,int r)
{
int L=id[l],R=id[r];
if(L==R) return query_sk(l,r);
else
{
int ans=query_sk(l,ll[L+1]-1)+query_sk(ll[R],r);
for(int i=L+1;i<R;i++) ans+=query_zk(i);
return ans;
}
}
void update(int l,int r)
{
int L=id[l],R=id[r];
if(L==R) update_sk(l,r,L);
else
{
update_sk(l,ll[L+1]-1,L);
update_sk(ll[R],r,R);
for(int i=L+1;i<R;i++) update_zk(i);
}
}
signed main()
{
int m;
cin>>n>>m;
build();
while(m--)
{
int op,l,r;
cin>>op>>l>>r;
l++,r++;
if(op==0) update(l,r);
else cout<<query(l,r)<<endl;
}
return 0;
}

浙公网安备 33010602011771号