CF1148F Foo Fighters

dolphina發表於2024-07-01

牛逼貪心題

假設都是將總和正的變成負的,所以如果總和是負的,val取相反數

對於二進位制操作,我們一位一位考慮,想讓其二進位制下1的個數最好變成奇數,只能選一個數保留哪些1,所以我們保留一個1就能乘上-1,改變了奇偶性。貪心滿足無後效性,最優子結構,區域性最優解為全域性最優解,我們嘗試將一個數二進位制下最高位的位數的作為不同種類的劃分依據,想讓總和變負的,我們儘量讓每個種類的和為負的,假設我們考慮到第\(i\)位,這一位作為哪些數的最高位,我把他們加起來,如果小於0了,我要是更改還可能為正數,不優,不更改。如果大於0,考慮把這一位上數是1的都取反了,顯然當前就小於0了。現在來看一下為什麼沒有後效性:對於每一個種類,我從低到高考慮,假設有位數\(i\)>位數\(j\),我\(i\)取什麼值對\(j\)沒有影響,因為我最高位為\(i\)的數不可能第\(j\)位是1

如果從大到小去一位一位考慮的話,想滿足沒有後效性,就去按照最低位的1分類,一樣的

#include<bits/stdc++.h>
#define vd void 
#define int long long 
#define MAXN 300005
int gi(){
	char c;int x=0,f=0;
	while(!isdigit(c=getchar()))f|=(c=='-');
	while(isdigit(c))x=(x*10)+(c^48),c=getchar();
	return f?-x:x;
}
int n,val[MAXN],mask[MAXN],l1[MAXN];
int help(int x){for(int i=61;i>=0;i--)if((x>>i)&1)return i;return -1;}
signed main(){
	n=gi();int s=0,ans=0;
	for(int i=1;i<=n;i++)val[i]=gi(),mask[i]=gi(),s+=val[i],l1[i]=help(mask[i]);
	if(s<0)for(int i=1;i<=n;i++)val[i]=-val[i];
	for(int i=0;i<62;i++){
		int res=0;
		for(int j=1;j<=n;j++)if(l1[j]==i)res+=val[j];
		if(res>0){
			ans|=(1ll<<i);
			for(int j=1;j<=n;j++)if((mask[j]>>i)&1)val[j]=-val[j];
		}
	}
	printf("%lld\n",ans);
	return 0;
}

感覺比較神奇這道題,按位考慮是二進位制常用的操作,想讓貪心滿足無後效性不妨欽定某個劃分原則/依據