【算法】【二分】

17 阅读2分钟

Test Generator

题意简述
给定两个整数 ( s ) 和 ( m ),需要构造一个非负整数数组 ( a ),满足:

  1. 数组元素之和等于 ( s );
  2. 每个元素 ( a_i ) 的二进制位中,为 1 的位必须是 ( m ) 的二进制位中也为 1 的位(即 ( a_i & m = a_i ))。

要求判断是否存在这样的数组。若存在,输出数组的最小可能长度 ( n );否则输出 (-1)。

#include <bits/stdc++.h>  
using namespace std;  
using ll=long long;  
void so(){  
    ll s,m;cin>>s>>m;  
    ll ans=0;  
    int ok=0;  
    ll k=s;  
    for(int i=0;i<=62;i++){  
        if((m>>i)&1){  
            if(k%(1ll<<i)==0)ok=1;  
            break;  
        }//至少可以由最第低位构成  
    }if(ok==0){cout<<-1<<'\n';return;}  
    ll l=1,r=1e18;  
    while(l<=r){  
        ll mid=(l+r)/2;  
        s=k;  
        for(int i=62;i>=0;i--){  
            if((m>>i)&1){  
                ll d=min(mid,s/(1ll<<i));//优先用大的  
                //不可以超过mid次  
                s-=d*(1ll<<i);  
            }  
        }if(s>0){  
            l=mid+1;//不够再加  
        }else r=mid-1;  
        //最后l>r;  
        //当<=0,r去试更小的  
    }cout<<l<<'\n';  
}int main(){  
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);  
    int t;cin>>t;  
    while(t--){so();}  
}

注意与启示

1.求最短的,可以想到二分

2.先不要看s,m有1的话s马上减,最多只能减mid(大的数先能用几次先用)


Turtle vs. Rabbit Race: Optimal Trainings

#include<bits/stdc++.h>
using namespace std;
#define int long long 
signed main(){
	int t=1;cin>>t;
	while(t--){
	
	int n;cin>>n;
	vector<int>a(n+1);
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}int q;cin>>q;
	vector<int>ans;
	int ps[n+1];
	ps[0]=0;
	for(int i=1;i<=n;i++){ps[i]=ps[i-1]+a[i];	
	}
	while(q--){
		int l,u;cin>>l>>u;
		int lb=l,rb=n;
		//二分找总段数<=u的最大r 
		while(lb<rb){
			int mid=(lb+rb+1)/2;
			if(ps[mid]-ps[l-1]<=u){lb=mid;
			}else rb=mid-1;
		}
	int mu=-1e18;
	int op;
	for(int i=max(l,lb-2);i<=min(n,lb+2);i++){
		int t=ps[i]-ps[l-1];
		int ut=(u+(u-t+1))*t/2;
		if(ut>mu){mu=ut;op=i;
		
		}
	}ans.push_back(op);
	}for(int i=0;i<ans.size();i++)cout<<ans[i]<<' ';
	cout<<'\n';
}
	return 0;
}

代码解析和注意事项

1.当二分求最大值时,要向上取整:向下可能会导致有些值无法取到

2.有想到前缀和,但是没想到二分(或许upper_bound就是二分)

3.我想到了二分,但是没想到误差怎么处理,但是想想其实就是在lb+1和lb上选,因为lb+1中已经有负的了,所以直接二分再在附近找