Codeforces Round 882 (Div. 2)(A-D) 题解

A. The Man who became a God

题意

给出一个序列,以及要求把这个序列划分为多少段,求这些段中差分数组之和最小为多少

题解

已给出需划分成m段,即要求删去m-1差分数组中的元素,直接排序然后删去最大的

code

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define ll long long
#define NO cout<<"NO"<<endl
#define YES cout<<"YES"<<endl
#define rep(i,a,b)   for(int i=a;i<=b;i++)
const int mod = 1e9 + 7;
const int N = 2e6 + 10;
ll inf = (1ll << 60);

//priority_queue <int,vector<int>,less<int> > p;
//priority_queue <int,vector<int>,greater<int> > q;
int a[N],b[N];
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int T = 1;
	cin >> T;
	while (T--)
	{
		int n,k;
		cin>>n>>k;
		rep(i,1,n)	cin>>a[i];
		int ans=0;
		rep(i,2,n)
		{
			b[i-1]=abs(a[i]-a[i-1]);
			ans+=b[i-1];
		}
		sort(b+1,b+n);
		k--;
		for(int i=n-1;i>=1;i--)
		{
			if(k==0)	break;
			if(k)	ans-=b[i];
			k--;
			
		}
		cout<<ans<<endl;
	}
	
	
}

B. Hamon Odyssey

题意

给出一个序列,设该序列被划分为m块,使每块连续取&,每块的值为x[i],在所有x[i]的和最小的情况下求最多的块数

题解

已知a&b<=a,a&b<=b,所以所有数取&一定最小,所有数取&的记为t

若t=0,则只需要找取&后为0的块数

若t>0,则划分成一块即可,可证明没有比这种情况更小的

code

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define ll long long
#define NO cout<<"NO"<<endl
#define YES cout<<"YES"<<endl
#define rep(i,a,b)   for(int i=a;i<=b;i++)
const int mod = 1e9 + 7;
const int N = 2e6 + 10;
ll inf = (1ll << 60);

//priority_queue <int,vector<int>,less<int> > p;
//priority_queue <int,vector<int>,greater<int> > q;
int a[N];
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int T = 1;
	cin >> T;
	while (T--)
	{
		int n;
		cin>>n;
		rep(i,1,n)	cin>>a[i];
		int t=a[1];
		rep(i,1,n)	t&=a[i];
		if(t!=0)
		{
			cout<<1<<endl;
			continue;
		}
		int x=a[1];
		int ans=0;
		rep(i,1,n)
		{
			x&=a[i];
			if(x==0)
			{
				x=a[i+1];
				ans++;
			}
		}
		cout<<ans<<endl;
	
		
	}
	
	
}

C. Vampiric Powers, anyone?

题意

给出一个长度为n的序列a,现在可以选择一个序列下标i,并向序列后添加一个元素,设添加元素为x,则x=a[i]^...a[m] (x为第m+1个元素),问可以添加的最大的x值是什么

题解

题目实际上每次新增的元素都会放在序列末尾,并且无法忽略,所以本质上可以转化为求某一段区间的最大异或和

code

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define ll long long
#define NO cout<<"NO"<<endl
#define YES cout<<"YES"<<endl
#define rep(i,a,b)   for(int i=a;i<=b;i++)
const int mod = 1e9 + 7;
const int N = 2e6 + 10;
ll inf = (1ll << 60);

//priority_queue <int,vector<int>,less<int> > p;
//priority_queue <int,vector<int>,greater<int> > q;

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int T = 1;
	cin >> T;
	while (T--)
	{
		int n;
		cin >> n;
		vector<int>a(n), nums;
		rep(i, 0, n - 1)	cin >> a[i];
		int x = 0;
		nums.push_back(0);
		rep(i, 0, n - 1)
		{
			x ^= a[i];
			nums.push_back(x);
		}
		
		x = 0;
		
		for (int k = 30; k >= 0; --k)
		{
			unordered_set<int> seen;
			for (int num : nums)	seen.insert(num >> k);
			int x_next = x * 2 + 1;
			bool found = false;
			
			for (int num : nums)
			{
				if (seen.count(x_next ^ (num >> k)))
				{
					found = true;
					break;
				}
			}
			
			if (found)	x = x_next;
			else		x = x_next - 1;
		}
		cout << x << endl;
	}


}

D. Professor Higashikata

题意

给出字符串s,区间个数m,例如对于字符串100110,区间(1,2),(1,2),(3,4),那么拼接后的字符串为101001

现在有q次修改,输入x,每次修改都会在使s[x]反转,即0->1,1->0,在后改后需要输出最少需要多少次交换(对s上的元素进行交换)可以使拼接后的字符串的字典序最大

题解

首先考虑到数据范围(n,m,q均为2e5),我们不可能真的去构建拼接后的字符串,所以考虑优化,只记录第一次出现的字符,

如样例中101001,实际上存储为1001,记为f,设1的个数为cnt1,对于f来讲,把前cnt1个元素全部置为1就是字典序最大的情况,所以只需要统计前cnt1个元素中有多少个0即可(此处还需考虑实际构建数组长度)

code

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define ll long long
#define NO cout<<"NO"<<endl
#define YES cout<<"YES"<<endl
#define rep(i,a,b)   for(int i=a;i<=b;i++)
const int mod = 1e9 + 7;
const int N = 2e6 + 10;
ll inf = (1ll << 60);

//priority_queue <int,vector<int>,less<int> > p;
//priority_queue <int,vector<int>,greater<int> > q;
struct BIT
{
	int s[N];
	int lowbit(int x)
	{
		return x & -x;
	}
	void update(int x, int y)
	{
		while (x < N)
		{
			s[x] += y;
			x += lowbit(x);
		}
	}
	int query(int x)
	{
		int res = 0;
		while (x)
		{
			res += s[x];
			x -= lowbit(x);
		}
		return res;
	}
} tr;
int l[N], r[N];
int id[N];
int tot = 0;
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int T = 1;
//	cin >> T;
	while (T--)
	{
		int n, m, q;
		string s;
		cin >> n >> m >> q >> s;
		s = ' ' + s;
		rep(i, 1, m)	cin >> l[i] >> r[i];
		set<int>num;
		rep(i, 1, n)	num.insert(i);
		rep(i, 1, m)
		{
			auto it = num.lower_bound(l[i]);
			while (it != num.end() && (*it) <= r[i] )
			{
				int x = *it;
				it++;
				num.erase(x);
				id[x] = ++tot;
			}
		}
		int limit = tot;
		int cnt1 = 0;
		for (auto x : num)	id[x] = ++tot;
		rep(i, 1, n)
		{
			if (s[i] == '1')	cnt1++;
			else
			{
				tr.update(id[i], 1);
			}
		}
		while (q--)
		{
			int x;
			cin >> x;
			if (s[x] == '1')
			{

				cnt1--;
				tr.update(id[x], 1);
				int sum = min(cnt1, limit);
				cout << tr.query(sum) << endl;
				s[x] = '0';
			}
			else
			{
				cnt1++;
				tr.update(id[x], -1);
				int sum = min(cnt1, limit);
				cout << tr.query(sum) << endl;
				s[x] = '1';
			}
		}




	}


}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值