Codeforces Round #772 (Div. 2) 解题报告

A. Min Or Sum

题意 :给你一个长度为n的数组,你可以进行多次以下操作
选择两个不同的整数 i 与 j, 用符合 \(a_i | a_j = x | y\) 的 x 和 y 替换他们
问这个数组和的最小值

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
#include <vector>
#include <stack>
#include <set>
#include <sstream>
#include <fstream> 
#include <cmath>
#include <iomanip>
#include <unordered_map>
#include <unordered_set>
#define x first
#define y second
#define ios ios::sync_with_stdio(false),cin.tie(0);
#define endl '\n'
#define pb push_back
#define all(x) x.begin(),x.end()
#define all1(x) x.begin()+1,x.end()
#define pi 3.14159265358979323846
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
 
const int N = 200010,M = 200010,INF = 0x3f3f3f3f,mod = 1e9 + 10;
const double INFF = 0x7f7f7f7f7f7f7f7f;
 
int n,m,k,t;

int main()
{
	ios;
	cin >> t;
	while(t --)
	{
		cin >> n;

		vector<int> a(n + 1);
		for(int i = 1;i <= n;i ++) cin >> a[i];
		int ans = a[1];
		for(int i = 2;i <= n;i ++) ans |= a[i];
		cout << ans << endl;
	}
	return 0;
}

B. Avoid Local Maximums

题意 : 给定一个数组,可以用任意数字替换数组中的数字,问使得数组不存在极大值的最小操作数,并要求输出操作后的数组
分析 : 线性扫一遍,遇到极大值,将其后的元素变大

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
#include <vector>
#include <stack>
#include <set>
#include <sstream>
#include <fstream> 
#include <cmath>
#include <iomanip>
#include <unordered_map>
#include <unordered_set>
#define x first
#define y second
#define ios ios::sync_with_stdio(false),cin.tie(0);
#define endl '\n'
#define pb push_back
#define all(x) x.begin(),x.end()
#define all1(x) x.begin()+1,x.end()
#define pi 3.14159265358979323846
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
 
const int N = 200010,M = 200010,INF = 0x3f3f3f3f,mod = 1e9 + 10;
const double INFF = 0x7f7f7f7f7f7f7f7f;
 
int n,m,k,t;

int main()
{
	ios;
	cin >> t;
	while(t --)
	{
		cin >> n;
		vector<int> a(n + 2);
		for(int i = 1;i <= n;i ++) cin >> a[i];
		int ans = 0;
		for(int i = 3;i <= n;i ++)
		{
			if(a[i - 1] > a[i - 2] && a[i - 1] > a[i])
			{
				ans ++; 
				a[i] = max(a[i - 1],a[i + 1]);
			}
		}

		cout << ans << endl;
		for(int i = 1;i <= n;i ++) cout << a[i] << ' ';
		cout << endl;
	}
	return 0;
}

C. Differential Sorting

题意 :给定一个数组,定义操作:
任选三个不同的数字 x, y, z, (\(x < y < z\)),使 \(a_x = a_y - a_z\)
问是否能将这个数组构造为非递减的,并将操作输出

分析 : 观察最后两个数,他们是不能被操作的
1.如果\(a_{n - 1} > a_n\) 则不能构造出非递减数组
2.如果\(a_n < 0\)\(a_{n - 1} - a_n\) 相当于是增加了,所以,如果存在 i使 \(a_i > a_{i + 1}\) 则无法构造
3.其他情况使\(a_1 ~ a_{n - 2}\) 都为 \(a_{n - 1} - a_n\)

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
#include <vector>
#include <stack>
#include <set>
#include <sstream>
#include <fstream> 
#include <cmath>
#include <iomanip>
#include <unordered_map>
#include <unordered_set>
#define x first
#define y second
#define ios ios::sync_with_stdio(false),cin.tie(0);
#define endl '\n'
#define pb push_back
#define all(x) x.begin(),x.end()
#define all1(x) x.begin()+1,x.end()
#define pi 3.14159265358979323846
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
 
const int N = 200010,M = 200010,INF = 0x3f3f3f3f,mod = 1e9 + 10;
const double INFF = 0x7f7f7f7f7f7f7f7f;
 
int n,m,k,t;

int main()
{
	ios;
	cin >> t;
	while(t --)
	{
		cin >> n;
		vector<int> a(n + 1,-INF);
		for(int i = 1;i <= n;i ++) cin >> a[i];
		
		if(a[n - 1] > a[n]) cout << -1 << endl;
		else
		{
			if(a[n] < 0 )
			{
				bool success = true;
				for(int i = 1;i < n;i ++) if(a[i] > a[i + 1]) success = false;
				if(success) cout << 0 << endl;
				else cout << -1 << endl;
				continue;
			}
			cout << n - 2 << endl;
			for(int i = 1;i <= n - 2;i ++) cout << i << ' '<< n - 1 << ' ' << n << endl;
		}
	}
	return 0;
}

D. Infinite Set(好题)

题意 : 给定一个数组,和 数字 p
定义集合 S , S 的元素符合以下条件
1.\(x = a_i (1 <= i <= n)\)
2.\(x = 2 y + 1 (y \in S)\)
3.\(x = 4 y(y \in S)\)

问S中不超过\(2 ^ p\) 的元素个数
\(2 ^ p\) 提示我们考虑二进制,在二进制下上述曹操为
2. x = y << 1 | 1
3. x = y << 2
直白的说,2就是给x的二进制右位补一个1,3就是给x的二进制下右位补两个0
考虑 dp
任何一位上的1 都是由以上两种方式转换过来的
所以 转移方程 : \(f(i) = f(i - 1) + f(i - 2)\)
再考虑每一个数组中的数,如果他可以由数组中的其他数经一系列转换过来,则不考虑他
对于每一个考虑的数,我们将其贡献记为其最高位1所在位数

每一位上的1获得的方案数为 \(f(i)\) , 则 每个数的则集合中的最高位不超 i的数量为\(\sum_1^i f(i)\)
最后加起来就好

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
#include <vector>
#include <stack>
#include <set>
#include <sstream>
#include <fstream> 
#include <cmath>
#include <iomanip>
#include <unordered_map>
#include <unordered_set>
#define x first
#define y second
#define ios ios::sync_with_stdio(false),cin.tie(0);
#define endl '\n'
#define pb push_back
#define all(x) x.begin(),x.end()
#define all1(x) x.begin()+1,x.end()
#define pi 3.14159265358979323846
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
 
const int N = 200010,M = 200010,INF = 0x3f3f3f3f,mod = 1e9 + 7;
const double INFF = 0x7f7f7f7f7f7f7f7f;
 
int n,m,k;

int main()
{
	ios;

	cin >> n >> k;
	vector<int> a(n + 1),f(N,0);
	unordered_map<int,bool> mp;
	for(int i = 1;i <= n;i ++) cin >> a[i];

	sort(all1(a));
	
	for(int i = 1;i <= n;i ++)
	{
		int t = a[i];
		while(t)
		{
			if(t == 1) break;
			else if(mp[t]) break;
			if(t & 1) t >>= 1;
			else if(t % 4 == 0) t /= 4;
			else break;
		}

		if(!mp[t])
		{
			mp[a[i]] = true;
			int len = 0;
			while((1LL << len) < a[i]) len ++;
			if((1LL << len) == a[i]) f[len + 1] ++;
			else f[len] ++;

		}
	}

	for(int i = 2;i <= k;i ++) f[i] = (f[i] + f[i - 1] + f[i - 2]) % mod;

	LL sum = 0;
	
	for(int i = 1;i <= k;i ++) sum = (sum + f[i]) % mod;

	cout << sum << endl;
	

	return 0;
}
posted @ 2022-07-01 11:38  notyour_young  阅读(23)  评论(0编辑  收藏  举报