AcWing 刷题2
AcWing 1227.分巧克力
思路
首先可以确定是二分,然后就是实现的细节,最开始我左边界设为1,右边界是把所有巧克力的总面积计算出来再除以小朋友的数量(最理想情况下),结果怎么都不对,后来想起来,二分的话,左右边界很大也没太大问题,因为只需要几次就会到正常区间了。所以直接把右边界设为100005了,这才算是对的.....中间真的冥思苦想不知道哪里出错了,气死了。
题解
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
int h[N],w[N];
int n,k;
int main(void)
{
cin>>n>>k;
int sum=0;
for(int i=0;i<n;i++)
cin>>h[i]>>w[i];
int l=1,r=100005,m;
while(l<r)
{
int q=k;//小朋友数量
m=(l+r+1)/2;
for(int i=0;i<n;i++)
q-=(h[i]/m)*(w[i]/m);
if(q>0) r=m-1;
else l=m;
}
cout<<l<<endl;
return 0;
}
AcWing 795.前缀和
思路
就是最基础的前缀和的思路,用一个数组F,Fi表示前i个元素的和,求区间l和r之间的数的和,只需要求Fi-Fi-1就行了
题解
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
int f[N];
int n,m,x,l,r;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>x;
f[i]=f[i-1]+x;
}
while(m--)
{
cin>>l>>r;
cout<<f[r]-f[l-1]<<endl;
}
return 0;
}
AcWing 796.子矩阵的和
思路
和前缀合一样的原理,只不过变成了二维。(感觉和小时候数学题里的求不规则图形的面积有点相似,容斥原理)
重点在这两句:
f[i][j]+=f[i][j-1]+f[i-1][j]-f[i-1][j-1];
cout<<f[c][d]-f[a-1][d]-f[c][b-1]+f[a-1][b-1]<<endl;//这个下标折磨了我半天
题解
#include<bits/stdc++.h>
using namespace std;
const int N=1005,M=1005;
int f[N][M],s[N][M];
int n,m,q;
int main()
{
int a,b,c,d;
cin>>n>>m>>q;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>f[i][j];
f[i][j]+=f[i][j-1]+f[i-1][j]-f[i-1][j-1];
}
while(q--)
{
cin>>a>>b>>c>>d;
cout<<f[c][d]-f[a-1][d]-f[c][b-1]+f[a-1][b-1]<<endl;
}
return 0;
}
AcWing 99.激光炸弹
思路
跟子矩阵的和很像,只是有几点需要注意,我写的时候遇到了很多问题。
如果正方形的边长大于地图中最大的横纵坐标,相当于每个点都能覆盖到,那么直接把边长改为最大的横纵坐标的那个就好了
还有,在求二维前缀和矩阵的时候,忘记了加i,j位置本身的值....
题解
#include<bits/stdc++.h>
using namespace std;
const int N=5005;
int f[N][N];
int n,m,h,l,x,y,w,ans;
int main()
{
cin>>n>>m;
if(m>5001) m=5001;
h=m;
l=m;
while(n--)
{
cin>>x>>y>>w;
f[++x][++y]+=w;
h=max(h,x);
l=max(l,y);
}
for(int i=1;i<=h;i++)
for(int j=1;j<=l;j++)
f[i][j]=f[i][j-1]+f[i-1][j]-f[i-1][j-1]+f[i][j];
for(int i=m;i<=h;i++)
for(int j=m;j<=l;j++)
ans=max(ans,f[i][j]-f[i-m][j]-f[i][j-m]+f[i-m][j-m]);
cout<<ans<<endl;
return 0;
}