【ybt金牌导航8-1-2】【luogu P4570】元素

元素

题目链接:ybt金牌导航8-1-2 / luogu P4570

题目大意

有一个物品,它有序号和贡献。
你可以选若干个物品,使得每个物品的序号都不会由其它选中的其中几个物品序号异或而成。

要你使得选中物品的总贡献最大。
输出这个最大总贡献。

思路

这道题看到一个选中的数不能被其它选中的数异或而成,就会想到用线性基来做。

但是这时候有个问题,线性基并不唯一,要怎么安排插入方式,才能使得总贡献最大。
那先插入的就肯定是能选就选,我们考虑贪心,按物品的贡献从大到小依次插入。

那这个贪心是否正确呢?答案是可以的。
首先,根据线性基的特点你可以知道线性基中的数的个数一定是确定的。
那你肯定就是有大的选大的,这就十分显然了。

代码

#include<cstdio>
#include<algorithm>
#define ll long long

using namespace std;

struct node {
    
    
	ll num;
	int mag;
}a[1001];
int n, ans;
ll f[101];

bool cmp(node x, node y) {
    
    
	return x.mag > y.mag;
}

bool add(ll x) {
    
    //线性基插入一个数
	for (int i = 63; i >= 0; i--)
		if ((x >> i) & 1) {
    
    
			if (!f[i]) {
    
    
				f[i] = x;
				return 1;
			}
			else x ^= f[i];
		}
	
	return 0;
}

int main() {
    
    
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf("%lld %d", &a[i].num, &a[i].mag);
	
	sort(a + 1, a + n + 1, cmp);//贪心思想,按贡献排序
	
	for (int i = 1; i <= n; i++) {
    
    
		if (add(a[i].num)) ans += a[i].mag;//可以被放进线性基中,加贡献
	}
	
	printf("%d", ans);
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43346722/article/details/114087842