蓝桥杯训练 | 二分和前缀和 | 02
数的范围
#include<bits/stdc++.h>
using namespace std;
const int N=100000+10;
int q[N];
int n,t;
int bsearch1(int x,int l,int r){
while(l<r){
int mid=l+r>>1;
if(q[mid]>=x)r=mid;
else l=mid+1;
}
return q[l]!=x?-1:l;
}
int bsearch2(int x,int l,int r){
while(l<r){
int mid=l+r+1>>1;
if(q[mid]<=x)l=mid;
else r=mid-1;
}
return q[l]!=x?-1:l;
}
int main(){
cin >> n >> t;
for(int i=0;i<n;i++)cin>>q[i];
while(t--){
int x;
cin >> x;
printf("%d %d",bsearch1(x,0,n-1),bsearch2(x,0,n-1));
}
return 0;
}
数的三次方根
#include<bits/stdc++.h>
using namespace std;
int main(){
double x;
cin >> x;
double l=-10000,r=10000,exp=1e-8;
while(r-l>=exp){
double mid=(l+r)/2;
if(pow(mid,3)<=x)l=mid;
else r=mid;
}
printf("%.6lf\n",l);
return 0;
}
前缀和
#include<bits/stdc++.h>
using namespace std;
const int N=100000+10;
int q[N],s[N];
int main(){
int n,T;
cin >> n >> T;
for(int i=1;i<=n;i++){
cin >> q[i];
s[i]=s[i-1]+q[i];
}
while(T--){
int l,r;
cin >> l >> r;
cout << (s[r]-s[l-1]) << endl;
}
}
子矩阵的和
#include<bits/stdc++.h>
using namespace std;
const int N=1000+10;
int n,m,T,q[N][N],s[N][N];
int main(){
scanf("%d%d%d",&n,&m,&T);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&q[i][j]);
s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+q[i][j];
}
}
while(T--){
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
int res = s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
printf("%d\n",res);
}
return 0;
}
机器人跳跃问题
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int h[N],n;
bool check(int x){
for(int i=1;i<=n;i++){
x = 2*x - h[i];
if(x<0)return false;
if(x>1e5)return true;
}
return true;
}
int main(){
cin >> n;
for(int i=1;i<=n;i++)scanf("%d",&h[i]);
int l=0,r=1e5;
while(l<r){
int mid = l + r >> 1;
if(check(mid))r=mid;
else l=mid+1;
}
cout << l << endl;
return 0;
}
四平方和
三重循环的做法
#include<bits/stdc++.h>
using namespace std;
int main(){
int x;
cin >> x;
for(int a=0;a*a<=x;a++){
for(int b=a;a*a+b*b<=x;b++){
for(int c=b;a*a+b*b+c*c<=x;c++){
int dd = x - a*a - b*b - c*c; // dd是d**2
double d = sqrt(dd);
if(d==(int)d){
printf("%d %d %d %d\n",a,b,c,(int)d);
return 0;
}
}
}
}
return 0;
}
哈希表做法
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
unordered_map<int,PII> S;
int main(){
int x;
cin >> x;
for(int c=0;c*c<=x;c++){
for(int d=c;c*c+d+d<=x;d++){
int t= c*c + d*d;
if(S.count(t)==0)S[t]={c,d};
}
}
for(int a=0;a*a<=x;a++){
for(int b=a;a*a+b*b<=x;b++){
int t = x - a*a - b*b;
if(S.count(t)){
printf("%d %d %d %d\n",a,b,S[t].first,S[t].second);
return 0;
}
}
}
return 0;
}
分巧克力
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int h[N],w[N];
int n,k;
bool check(int x){
int s=0;
for(int i=0;i<n;i++){
s+=(h[i]/x)*(w[i]/x);
if(s>=k)return true;
}
return s>=k;
}
int main(){
cin >> n >> k;
for(int i=0;i<n;i++){
scanf("%d%d",&h[i],&w[i]);
}
int l=1,r=1e5;
while(l<r){
int mid=l+r+1>>1;
if(check(mid))l=mid;
else r=mid-1;
}
cout << l << endl;
return 0;
}
激光炸弹
#include<bits/stdc++.h>
using namespace std;
const int N=5000+10;
int s[N][N];
int main(){
int T,r;
cin >> T >> r;
int xx=r,yy=r; // 边界
while(T--){
int x,y,w;
cin >> x >> y >> w;
x++,y++;
xx=max(xx,x),yy=max(yy,y);
s[x][y]+=w;
}
// 预处理前缀和
for(int i=1;i<=xx;i++){
for(int j=1;j<=yy;j++){
s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
}
}
int res = -(1<<30);
for(int i=r;i<=xx;i++){
for(int j=r;j<=yy;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;
}
K倍区间
O(n**2)
做法
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int s[N];
int main(){
int n,k;
cin >> n >> k;
for(int i=1;i<=n;i++){
scanf("%d",&s[i]);
s[i]+=s[i-1];
}
int res=0;
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
int t=s[j]-s[i-1];
if(t%k==0)res++;
}
}
cout << res << endl;
return 0;
}
O(n)
做法
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+10;
LL s[N],cnt[N];
int main(){
int n,k;
cin >> n >> k;
for(int i=1;i<=n;i++){
scanf("%ld",&s[i]);
s[i]+=s[i-1];
}
LL res=0;
cnt[0]=1;
for(int i=1;i<=n;i++){ // 枚举右端点
res+=cnt[s[i]%k];
cnt[s[i]%k]++;
}
cout << res << endl;
return 0;
}