前缀和
Q:给出一个长度为n的数组A[],并进行q组询问,每次询问给出一个区间[l,r],需要求区间[l,r]的数组元素和。
A:令前缀和数组sum[i]=A[1]+...+A[i]
sum[r]=A[1]+A[2]+...+A[l-1]+A[i]+...+A[r]
A[l]+...A[r]=sum[r]-sum[l-1]
每次询问O(1),总复杂度O(q)=1
- 给定一个长度为N的数列,A1,A2...AN,如果其中一段连续的子序列Ai,Ai+1...Aj(i<=j)之和是K的倍数,我们就称这个区间[i,j]是K倍区间。求出这个数列中共有多少个K倍区间。
//朴素前缀和,复杂度O(n2) scanf("%d%d",&n,&k); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i];//一边读数组,一边计算sum[i],没有额外的空间复杂度 } for(int i=1;i<=n;i++){ for(int j=i;j<=n;j++){ if((sum[j]-sum[i-1])%k==0){ ans++; } } } //竞赛中1s跑10^7位数的计算考虑优化:
-
利用公式(a-b)%k=(a%k-b%k)%k
-
把公式(sum[j]-sum[i-1])%k==0转换成sum[j]%k==sum[i-1]%k
-
用add[i]记录有多少个sum数组中的元素取模后为i。则从add[i]里任意挑选两个都符合sum[j]%k==sum[i-1]%k,结果为C
scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); sum[i]=(sum[i-1]+a[i])%k; add[sum[i]]++; } for(int i=0;i<k;i++) { ans+=add[i]*(add[i]-1)/2; } printf("%lld",ans+add[0]); -
最后答案为add[0]+add[i]*add[i-1]/2(为什么要再加一个add[0]?因为add[0]本来就是sum[i]%k==0的,本身算K倍区间,所以要再加上)
2.给定一个NxM的矩阵A,请你统计有多少个子矩阵(最小1x1,最大NxM)满足子矩阵中所有数的和不超过给定的整数K。
//朴素二维前缀和
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
}
int ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int x=i;x<=n;x++)
for(int y=j;y<=m;y++)
{
if(sum[x][y]-sum[x-i][y]-sum[x][y-j]+sum[x-i][y-j]<=k)
ans++;
}
printf("%d\n",ans);
二分法
算法模板
int check(int n){} //根据题目要求检查n是否满足条件
//找最小的满足check的值
int bsearch(int l,int r)
{
while(l<r)
{
int mid=(l+r+1)>> 1;//除2
if(check(mid))
r=mid;
else
l=mid+1;
}
return l;
}
//找最大的满足check的值
int bsearch(int l,int r)
{
while(l<r)
{
int mid=(l+r+1)>>1;
if(check(mid))
{
l=mid;
}
else
r=mid-1;
}
return l;
}
例题:

#include<bits/stdc++.h>
int N,K;
int H[100000],W[100000];
int w_m=0;
int main()
{
for(int i=1;i<=N;i++)
scanf("%d %d",&H[i],&W[i]);
for(int i=1;i<=N;i++)
{
w_m=max(w_m,H[i]);
w_m=max(w_m,W[i]);
}
int l=0,r=w_m;
while(l<r){
int m=(l+r+1)>>1;
if(check(m)) l=m;
else r=m-1;
}
printf("%d\n",l);
}
int check(a)
{
int cnt=0;
for(int i=1;i<=N;i++)
{
cnt+=(H[i]/a)*(W[i]/a);//如果a比边长还大的话,除完就为0了,就不加
if(cnt>=K)
return 1;
}
return 0;
}

被折叠的 条评论
为什么被折叠?



