CF1148F Foo Fighters(构造,贪心)
洛谷传送门
解题思路
按mask二进制位,把物品分类。
设sum[i]为mask共有i位的物品的val的和。
因为若答案的第i位为1,对mask小于i位的物品是没有影响的。
于是我们从低位向高位枚举,这样就保证了后面的决策不会影响前面已经决定了的状态。
因为只要求答案变成相反数,所以只要每一个sum[i]变成与总的sum异号即可。
同时,在更改当前位时,需要把当前位为1的每一个物品的val变成相反数并更新后面的sum。
感觉这不是一个真正意义上的贪心,其并不满足最优子结构的要求。
因为这样只能求出一组解,而不是最优解。
注意:用 1<<i 时,一定要写成 1ll<<i。
一天一个好习惯,noip不爆零。
AC代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=3e5+5;
int n,ans[65];
long long anss,sum[maxn],tot;
struct node{
long long val,mask;
}a[maxn];
vector<int> b[maxn];
inline void update(int i,int p){
int cnt=0;
long long x=a[i].mask;
if(x&(1ll<<(p-1))){
while(x>0){
x/=2;
cnt++;
}
sum[cnt]-=2*a[i].val;
a[i].val=-a[i].val;
}
}
int main(){
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].val>>a[i].mask;
tot+=a[i].val;
long long t=a[i].mask,cnt=0;
while(t>0){
t/=2;
cnt++;
}
b[cnt].push_back(i);
sum[cnt]+=a[i].val;
}
for(int i=1;i<=63;i++){
if((sum[i]!=0)&&(((sum[i]>0)^(tot>0))==0)){
ans[i]=1;
for(int j=1;j<=n;j++){
update(j,i);
}
}
}
for(int i=63;i>=1;i--){
anss=anss*2+ans[i];
}
cout<<anss;
return 0;
}