前缀和
一维前缀和
这个优化主要是用来在O(1)时间内求出一个序列a中,a[i]+a[i+1]+……+a[j]的和。
具体原理十分简单:用sum[i]表示(a[1]+a[2]+……+a[i]),其中sum[0]=0,则(a[i]+a[i+1]+……+a[j])即等于sum[j]-sum[i-1]。
二维前缀和
同理,有一维就有二维。对于一个矩阵a,我们也能在O(1)时间内求出子矩阵[x1~x2][y1~y2]的和。
设sum[i][j]为子矩阵[1~i][1~j]的和。则由容斥原理得:
sum[0][j]=sum[i][0]=0
a[x1~x2][y1~y2]=sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1]
应用问题
核心就两个字:降维。
面对许多高维问题,往往前缀和是最先想到的降维方法。
这样在降维的基础上,许多更进一步的优化才能实现。
题目点击打开链接
题意:有n家银行围成一个圈,有个人在有些银行里欠了钱,在一些银行里有存钱,欠的钱总数等于存的钱总数。
现在可以有操作,如果两个银行相邻,那么就能在一个银行转任意多的钱到另一个银行。问最少的操作次数,使得在所有银行的存款钱数都为0
思路:贪心,前缀和维护
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <cmath>
#define maxn 100005
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
int main(){
int n,m,ans;
ll a[maxn];
map<ll,int> b;
cin>>n;
ll sum=0;
memset(a,0x3f,sizeof(a));
for(int i=1;i<=n;i++){
cin>>a[i];
sum+=a[i];
b[sum]++;
ans=max(ans,b[sum]);
}
cout<<n-ans<<endl;
return 0;
}