分块学习笔记
分块学习笔记
区间加:
对于每个区间 \([l,r]\),如果 \(lid=rid\),那么就暴力加。否则中间块加到 \(sum[i]\) 和 \(tag[i]\) 内,其余散块暴力加到 \(a[i]\) 内。注意不会存在最后一个块长不为 \(len\) 的情况,因为 \(rid-1\) 总是不会在最后一个块内。
区间和:
对于每个区间 \([l,r]\),如果 \(lid=rid\),那么就暴力查,加的是 \(a[i]\) 和 \(tag[i]\)。否则中间块直接加 \(sum[id]\),左右散块暴力加 \(a[i]\) 和 \(tag[i]\)。记得处处取模。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+7;
int tag[N],belongs[N],cnt,a[N],sum[N];
int len;
int n;
void add(int l,int r,int x){
int lid=belongs[l],rid=belongs[r];
if(lid==rid){
for(int i=l;i<=r;i++) a[i]+=x,sum[lid]+=x;
return;
}
for(int i=l;belongs[i]==lid;i++) a[i]+=x,sum[lid]+=x;
for(int i=lid+1;i<rid;i++) tag[i]+=x,sum[i]+=len*x;
for(int i=r;belongs[i]==rid;i--) a[i]+=x,sum[rid]+=x;
}
int query(int l,int r,int p){
int lid=belongs[l],rid=belongs[r];
int ans=0;
if(lid==rid){
for(int i=l;i<=r;i++) ans+=a[i],ans%=p,a[i]+=tag[lid],ans%=p;
return ans%p;
}
for(int i=l;belongs[i]==lid;i++) ans+=a[i],ans%=p,ans+=tag[lid],ans%=p;
for(int i=lid+1;i<rid;i++) ans+=sum[i],ans%=p;
for(int i=r;belongs[i]==rid;i--) ans+=a[i],ans%=p,ans+=tag[rid],ans%=p;
return ans%p;
}
signed main(){
// freopen("data.in","r",stdin);
scanf("%lld",&n);
len=sqrt(n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
belongs[i]=(i-1)/len+1;
sum[belongs[i]]+=a[i];
}
for(int i=1;i<=n;i++){
int op,l,r,c;
scanf("%lld%lld%lld%lld",&op,&l,&r,&c);
if(op==0) add(l,r,c);
else printf("%lld\n",query(l,r,c+1));
}
return 0;
}
整除分块
#include<bits/stdc++.h>
using namespace std;
#define int long long
int division_block(int n){
int res=0;
for(int l=1,r;l<=n;l=r+1){
r=n/(n/l);
res+=n/l*(r-l+1);
}
return res;
}
int n;
signed main(){
cin>>n;
printf("%lld",division_block(n));
return 0;
}
根号算法优化DP
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+7;
const int mod=1e9+7;
const int MAXN=2e3+7;
int f[MAXN][N];
int n,k;
int cnt,block_len[N];
void init(){
for(int l=1,r;l<=n;l=r+1){
r=n/(n/l),block_len[++cnt]=r-l+1;
}
}
signed main(){
cin>>n>>k;
init();
for(int i=1;i<=cnt;i++) f[0][i]=1;
for(int i=1;i<=k;i++){
for(int j=1;j<=cnt;j++)
f[i][j]=(f[i][j]+(block_len[j]*f[i-1][cnt-j+1]%mod)%mod)%mod;
for(int j=1;j<=cnt;j++)
f[i][j]=(f[i][j]+f[i][j-1]%mod)%mod;
}
printf("%lld",f[k][cnt]%mod);
return 0;
}
根号
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+7;
int n,m,ans;
int d[N],A[N],B[N],vis[N];
vector<int> G[N];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&A[i],&B[i]);
++d[A[i]],++d[B[i]];
}
for(int i=1;i<=m;i++){
int u=A[i],v=B[i];
if(d[u]>d[v]) swap(u,v);
else if(d[u]==d[v]&&u>v) swap(u,v);
G[u].push_back(v);
}
for(int u=1;u<=n;u++){
for(int v:G[u]) vis[v]=u;
for(int v:G[u]){
for(int w:G[v]) if(vis[w]==u) ++ans;
}
}
printf("%d",ans);
return 0;
}