1.前缀和【一维】
#include <bits/stdc++.h>
using namespace std;
const int N=100005;
int a[N],s[N];
int main()
{
s[0]=0;
int n,m,l,r;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) s[i]=a[i]+s[i-1];
while(m--)
{
scanf("%d%d",&l,&r);
printf("%d\n",s[r]-s[l-1]);
}
return 0;
}
1230.k倍区间【太难了,想了俩小时,好多需要注意的细节】
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef long long ll;
int n,k;
int a[N];
ll s[N],cnt[N];
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
s[i]=s[i-1]+a[i];
}
cnt[0]=1;//前缀和预处理余数
ll res=0;
for(int i=1;i<=n;i++)
{
res+=cnt[s[i]%k];
cnt[s[i]%k]++;
}
printf("%lld\n",res);
return 0;
}
2.子矩阵的和【二维前缀和】
方法一:二维前缀和
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int a[N][N],s[N][N];
int main()
{
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
for(int i=1; i<=n; i++)
{
s[i][0]=0;
for(int j=1; j<=m; j++)
{
scanf("%d",&a[i][j]);
s[i][j]=a[i][j]+s[i][j-1];
}
}
int x1,x2,y1,y2;
while(q--)
{
int sum=0;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
for(int i=x1; i<=x2; i++)
{
sum+=s[i][y2]-s[i][y1-1];
}
printf("%d\n",sum);
}
return 0;
}
方法二:容斥原理
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int m,n,q;
int a[N][N],b[N][N];
int main(){
cin>>n>>m>>q;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++ )
cin>>a[i][j];
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
b[i][j]=b[i-1][j]+b[i][j-1]-b[i-1][j-1]+a[i][j];
while(q--)
{
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
printf("%d\n",b[x2][y2]-b[x1-1][y2]-b[x2][y1-1]+b[x1-1][y1-1]);
}
return 0;
}
激光炸弹【二维前缀和的经典应用】,细节很要命,开始都没看明白题意\冷汗
#include <bits/stdc++.h>
using namespace std;
const int N=5010;
int n,m;
int s[N][N];
int main()
{
int cnt,R;
cin>>cnt>>R;
n=m=R;
while(cnt--)
{
int x,y,w;
cin>>x>>y>>w;
x++,y++;//前缀和下标从1开始
n=max(n,x),m=max(m,y);//n,m表示区域边界
s[x][y]+=w;
}
for(int i=1;i<=n;i++)//预处理前缀和
for(int j=1;j<=m;j++)
s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
int res=0;
//枚举所有边长是R的矩形,(i,j)为右下角
for(int i=R;i<=n;i++)
for(int j=R;j<=m;j++)
res=max(res,s[i][j]-s[i-R][j]-s[i][j-R]+s[i-R][j-R]);
cout<<res<<endl;
return 0;
}
523.组合数问题,很巧妙的构造了一个01矩阵,转化成二维前缀和
#include <bits/stdc++.h>
using namespace std;
const int N=2010;
int c[N][N];
int s[N][N];
int main()
{
int T,k;
cin>>T>>k;
for(int i=0;i<N;i++)
{
for(int j=0;j<=i;j++)
{
if(!j) c[i][j]=1%k;
else c[i][j]=(c[i-1][j]+c[i-1][j-1])%k;
}
}
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
{
if(j<=i&&c[i][j]==0) s[i][j]=1;
if(i-1>=0) s[i][j]+=s[i-1][j];
if(j-1>=0) s[i][j]+=s[i][j-1];
if(i-1>=0&&j-1>=0) s[i][j]-=s[i-1][j-1];
}
while(T--)
{
int n,m;
cin>>n>>m;
cout<<s[n][m]<<endl;
}
return 0;
}
3.差分【一维差分】
#include <bits/stdc++.h>
using namespace std;
const int N=100010;
int a[N],b[N];
void insertt(int l,int r,int c)
{
b[l]+=c;
b[r+1]-=c;
}
int main()
{
int m,n;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++) insertt(i,i,a[i]);
int l,r,c;
while(m--)
{
scanf("%d%d%d",&l,&r,&c);
insertt(l,r,c);
}
for(int i=1;i<=n;i++) b[i]+=b[i-1];
for(int i=1;i<=n;i++) printf("%d ",b[i]);
return 0;
}
4.差分矩阵【二维差分】
方法一:容斥原理
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int a[N][N],b[N][N];
void inserrtt(int x1,int y1,int x2, int y2, int c)
{
b[x1][y1]+=c;
b[x2+1][y1]-=c;
b[x1][y2+1]-=c;
b[x2+1][y2+1]+=c;
}
int main()
{
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
inserrtt(i,j,i,j,a[i][j]);
}
}
while(q--)
{
int x1,x2,y1,y2,c;
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&c);
inserrtt(x1,y1,x2,y2,c);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
b[i][j]+=b[i][j-1]+b[i-1][j]-b[i-1][j-1];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
j==m?printf("%d\n",b[i][j]):printf("%d ",b[i][j]);
return 0;
}
方法二:二维差分
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int a[N][N],b[N][N];
void inserrtt(int x1,int y1,int x2, int y2, int c)
{
for(int i=x1;i<=x2;i++)
{
b[i][y1]+=c;
b[i][y2+1]-=c;
}
}
int main()
{
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
inserrtt(i,j,i,j,a[i][j]);
}
}
while(q--)
{
int x1,x2,y1,y2,c;
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&c);
inserrtt(x1,y1,x2,y2,c);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
b[i][j]+=b[i][j-1];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
j==m?printf("%d\n",b[i][j]):printf("%d ",b[i][j]);
return 0;
}