Codeforces Round 882 (Div. 2)(A-C)

目录

Problem - A - Codeforces

Problem - B - Codeforces

Problem - C - Codeforces


Problem - A - Codeforces

题意:给定长度为n的数组,要求把数组分成k个子段,并且让每个子段的绝对值之差的和最小。

思路:一开始拿到题目没有任何思路,只能先求出两两之间的绝对值之差,然后手玩了一下发现,要求分成k个子段正好是所有的绝对值之差减去(k-1)个最大的绝对值之差。

#include<bits/stdc++.h>

using namespace std;
const int N=3e5+5;
typedef long long ll;
typedef pair<ll,ll> pll;
int mod=1e9+7;
const int maxv=4e6+5;

int d[1005][1005];

void solve()
{	
	int n,k;
	cin>>n>>k;
	vector<int> a(n);
	for(auto &x: a) cin>>x;
	vector<int> b;
	ll sum=0;
	for(int i=1;i<n;i++){
		int x=abs(a[i]-a[i-1]);
		b.push_back(x);
		sum+=x;
	} 
	sort(b.begin(),b.end(),greater<int>());
	for(int i=0;i<k-1;i++){
		sum-=b[i];
	}
	cout<<sum<<endl;


}

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	t=1;
	cin>>t;
	while(t--){
		solve();
	}
	system("pause");
	return 0;
}

Problem - B - Codeforces

思路:贪心,我们可以知道,与运算,只有可能越运算越小,我们尽量让每次运算后的值为0即可,若出现了一次0,就重置一次,然后段数++,这样下来一定是最优的,最后注意特判一下段数为0的情况。

#include<bits/stdc++.h>

using namespace std;
const int N=3e5+5;
typedef long long ll;
typedef pair<ll,ll> pll;
int mod=1e9+7;
const int maxv=4e6+5;

int d[1005][1005];

void solve()
{	
	int n;
	cin>>n;
	vector<ll> a(n);
	int cnt=0;
	for(auto &x: a) cin>>x;
	ll sum=a[0];
	int f=0;
	for(int i=0;i<n;i++){
		ll val=sum&a[i];
		if(val==0){
			cnt++;
			sum=a[i+1];
		}
		else{
			sum=val;
		}
	}
	if(!cnt) cnt++;
	cout<<cnt<<endl;


}

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	t=1;
	cin>>t;
	while(t--){
		solve();
	}
	system("pause");
	return 0;
}

Problem - C - Codeforces

题意:对于某段从i-n的区间,生成一个新的数,为区间(i-n)的异或和,题目要求求出按照上述要求最大的异或和。

思路:对于某段从i-n的区间,异或和为a_{i}^a_{i+1}^........^a_{n},对于j<i时,异或和为aj^……an,又因为j<i,所以对于区间i-n的异或和被抵消了,则最后添加的是区间(j-i-1),那么此题就转化为了求子段的异或和最大值。

对于子区间异或和,有一个前置知识,即任意两数异或和最大值。

因为

数组的前缀异或和有这样一个规律:

设 x o r [ i ] = a [ 1 ] ⊕ a [ 2 ] ⊕ . . . ⊕ a [ n] ,则子数组 a r r [ i . . j ]  的异或和为:x o r [ j ] ⊕ x o r [ i − 1 ] 

于是我们可以这样做:求以每个元素作为子数组结尾的子数组的最大异或和,通过将 x o r [ 1 ] , x o r [ 2 ] , . . . , x o r [ i − 1 ]  分别插到 Trie 树中,然后查询 x o r [ i ] 与 Trie 树中的元素的最大异或值,此时就变成了上述 最大异或对 模型。

#include<bits/stdc++.h>

using namespace std;
const int N=1e5+5;
typedef long long ll;
typedef pair<ll,ll> pll;
int mod=1e9+7;
const int maxv=4e6+5;

vector<int> a(N);
int son[N*31][2],idx;
int n;
int s[N];

void add(int x)
{
	int p=0;
	for(int i=31;~i;i--){
		int &s=son[p][x>>i&1];
		if(!s) s=++idx;
		p=s;
	}
}

int query(int x)
{
	int p=0,res=0;
	for(int i=31;~i;i--){
		int c=x>>i&1;
		if(son[p][!c]){
			res+=1<<i;
			p=son[p][!c];
		}
		else p=son[p][c];
	}
	return res;
}

void solve()
{	
	cin>>n;
	idx=0;
	for(int i = 0; i < n*31; i ++){
    	//cnt[i] = 0;
    	son[i][1] = 0;
    	son[i][0] = 0;
    }
	for(int i=1;i<=n;i++){
		cin>>a[i];
		s[i]=s[i-1]^a[i];
	}
	int res=0;
	add(s[0]);
	for(int i=1;i<=n;i++){
		res=max(res,query(s[i]));
		add(s[i]);
	}
	cout<<res<<endl;

}

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	t=1;
	cin>>t;
	while(t--){
		solve();
	}
	system("pause");
	return 0;
}

解法二:因为此题值域比较小,所以可以直接暴力求出答案。

#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
using LL = long long;

int main(){

    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);

    int T;
    cin >> T;
    while(T--){
        int n;
        cin >> n;
        vector<int> a(n);
        for(int i = 0; i < n; i++) cin >> a[i];
        vector<bool> v(256);
        v[0] = true;
        int s = 0, ans = 0;
        for(int i = 0; i < n; i++){
            s ^= a[i];
            v[s] = true;
            for(int j = 0; j < 256; j++){
                if (v[j]){
                    ans = max(ans, s ^ j);
                }
            }
        }
        cout << ans << '\n';
    }

}

再给出一道和异或有关的题目:

题意:有两个操作:

操作1:对从x-y上的简单路径上的权值w进行异或。

操作2:给定点x,求出点周围权值的异或和。

思路:我们可以发现,对一条路径上的权值进行异或,边只异或了一次,但是对于除端点的点而言,每个点都是异或了两次,相当于没变,所以我们只需要对给定的端点进行修改即可。

#include<bits/stdc++.h>
#define endl '\n'

using namespace std;
const int N=3e6+5;
typedef long long ll;
typedef pair<ll,ll> pll;
int mod=1e9+7;
const int maxv=4e6+5;
int c[N];

void solve()
{	
	int n,q;
	cin>>n>>q;
	for(int i=1;i<=n-1;i++){
		int a,b,w;
		cin>>a>>b>>w;
		c[a]^=w,c[b]^=w;
	}
	while(q--){
		int op;
		cin>>op;
		if(op==1){
			int x,y,z;
			cin>>x>>y>>z;
			c[x]=c[x]^z,c[y]=c[y]^z;
		}
		else {
			int x;
			cin>>x;
			cout<<c[x]<<endl;
		}
	}
}

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	t=1;
	//cin>>t;
	while(t--){
		solve();
	}
	system("pause");
	return 0;
}

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值