前缀和
一维前缀和
常见的转移:
代码实例
给定一个字符串,每次询问一个区间[l,r],中有多少个字符c属于[‘a’,‘z’]
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e4;
int a[maxn][25],d[maxn][25]={0};
int main()
{
int i;
string str;
cin>>str;
str='#'+str;
cout<<str;
d[1][str[1]-'a']++;
for(i=2;str[i]!='\0';i++){
int v;
v=str[i]-'a';
for(int j=0;j<26;j++){
d[i][j]=d[i-1][j];
}
d[i][v]++;
}
int q;
cin>>q;
while(q--){
int j;
char c;
cin>>j>>c;
cout<<d[j][c-'a'];
}
return 0;
}
二维前缀和
给定一个二维矩阵,每次给定四个点代表矩阵范围,如何 O(1)的求该矩阵内所有数的和(简称矩阵和)
代码实例
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e4;
int a[maxn][maxn],d[maxn][maxn];
int main()
{
int n,m,i,j;
cin>>n>>m;
for(i=0;i<n;i++){
for(j=0;j<n;j++){
cin>>a[i][j];
}
}
d[0][0]=a[0][0];
for(i=1;i<n;i++){
d[0][i]=a[0][i]+d[0][i-1];
}
for(j=1;j<m;j++){
d[j][0]=a[j][0]+d[j-1][0];
}
for(i=1;i<n;i++){
for(j=1;j<n;j++){
d[i][j]=a[i][j]+d[i-1][j]+d[i][j-1]-d[i-1][j-1];
}
}
for(i=0;i<n;i++){
for(j=0;j<n;j++){
cout<<d[i][j]<<" ";
}
cout<<endl;
}
int q,x1,y1,x2,y2;
cin>>q;
while(q--){
cin>>x1>>y1>>x2>>y2;
cout<<d[x2][y2]-d[x1-1][y2]-d[x2][y1-1]+d[x1-1][y1-1];
}
return 0;
}
差分
作用:O(1)的做区间加法
例: 次操作,每次让下标在区间[l,r]的所有数加上x , 最后让你输出原数组的每个数
代码实例
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6;
int a[maxn],d[maxn];
int main()
{
int i,n;
cin>>n;
for(i=0;i<n;i++){
cin>>a[i];
}
d[0]=a[0];
int q;
cin>>q;
for(i=1;i<n;i++){
d[i]=a[i]-a[i-1];//对数组进行差分
}
while(q--){
int l,r,x;
cin>>l>>r>>x;
d[l]+=x;//加的区间,影响范围
d[r+1]-=x;
}
for(i=1;i<n;i++){
d[i]+=d[i-1];//进行前缀和还原数组
}
for(i=0;i<n;i++){
cout<<d[i]<<" ";
}
return 0;
}