Test Generator
题意简述
给定两个整数 ( s ) 和 ( m ),需要构造一个非负整数数组 ( a ),满足:
- 数组元素之和等于 ( s );
- 每个元素 ( 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中已经有负的了,所以直接二分再在附近找