Codeforces Round 888 (Div. 3)(A~F) ---Day11

1851A - Escalator Conversations 

        题意:给定n个人的高度h和你自己的高度H,给定一个数m和数字k,求你和某个人的高度差为k的倍数且0 < 高度差/k < m 的个数。

        思路:直接模拟即可。

        

void solve() 
{
	int n , m , k , H;
	cin>>n>>m>>k>>H;
	int h[n];
	for(int i = 0; i < n ; i ++)
		cin>>h[i];
	int ans = 0;
	for(int i =0 ; i < n ; i ++){
		int s = abs(h[i] - H);
		if(s!= 0 && s % k == 0){
			if(s / k < m)
				ans++;
		}
	}
	cout<

1851B - Parity Sort          

        题意:给定一个数组n,你可以交换奇偶性相同的两个数,求整个数组能否变为非递减序列。

        思路:首先记录原始数组的奇偶性,然后将奇数、偶数分为不同两组进行排序,然后再根据原数组的奇偶性按顺序填入奇数偶数,最后判断整个数组是否非递减。

void solve() 
{
	int n;
	cin>>n;
	vector odd,even;
	int a[n];
	for(int i = 0; i < n ; i ++){
		cin>>a[i];
		if(a[i]%2 == 1){
			odd.pb(a[i]);
		}
		else{
			even.pb(a[i]);
		}
	}
	sort(odd.begin() , odd.end() , cmp);
	sort(even.begin() , even.end() ,cmp);
	int ans[n],cnt1 = 0 , cnt0 = 0;
	for(int i = 0; i < n ; i ++){
		if(a[i] % 2 == 0){
			ans[i] = even[cnt0++];
		}
		else
			ans[i] = odd[cnt1++];
	}
	int f = 1;
	for(int i = 1 ; i < n ; i ++){
		if(ans[i] < ans[i - 1]){
			cout<<"NO\n";	
			return;	
		}
	}
	cout<<"YES\n";
}   

1851C - Tiles Comeback 

        题意:给定一个整数k和长度为n的格子,每个格子有一个数字。你需要从a_{1}跳跃到a_{k}。规定你可以向右跳跃任意数量,你的路径为每次所在格子的数。路径从前往后可以分为若干个长度为k的块,且每个块之内的数相同。

        思路:已知开始所在a_{1},最后所在a_{n}。根据贪心思想,若a_{1} \neq a_{n}时,只需要满足路径当中前k个数为a_{1},后k个数为a_{n}即可。若a_{1} = a_{n}时,只需要满足共有k个数为a_{1}即可。

void solve() 
{
	int n , k;
	cin>>n>>k;
	int c[n + 5];
	for(int i = 1; i <= n ; i ++){
		cin>>c[i];
	}
	int end = n;
	int cnt = 0;
	if(c[1] == c[n]){
		for(int i = 1 ; i<= n ; i++){
			if(c[i] == c[1])
				cnt++;
		}
	}
	else{
		for( ; end>0;end--){
		if(c[end] == c[n])
			cnt++;
		if(cnt == k)
			break;
		}
		cnt = 0;
		for(int i = 1 ; i< end ; i++){
			if(c[i] == c[1])
				cnt++;
		}
	}
	if(cnt >= k)
		cout<<"YES";
	else
		cout<<"NO";
	cout<

1851D - Prefix Permutation Sums 

        题意:有一个长度为n的数组,给定了其前缀和数组,其中前缀和数组中缺失了一个。求补全前缀和数组后能否使得原数组为一个排列(排列的定义为1~n所有的数有且仅有1个)。

        思路:通过前缀和数组我们可以得到n - 1 个数字。此时分两种情况来讨论:1、前缀和数组的尾缺失了。2、前缀和数组缺失了其余位置数。情况1:尾部缺失,如果得到的n-1个数字可以与排列中的不同数字一一对应,那么加上尾部后能够组成序列。情况2:中间缺失的话,这n - 1个数当中有一个数代表了原数组中的a_{i} + a_{i + 1}。若n - 2个数能与原序列当中不同数字一一对应,且剩下的两个没有对应数字相加为余下的那一个数,则能够组成序列。综上,只需要记录一下有多少个数字能与序列匹配然后再判断即可。

void solve() 
{
	int n;
	cin>>n;
	LL sum[n + 5];
	sum[0] = 0;
	int isv[n + 5];
	memset(isv , 0 , sizeof isv);
	for(int i = 1; i < n ;i ++){
		cin>>sum[i];
	}
	queueidx;
	for(int i = 1 ; i < n ; i ++){
		idx.push(sum[i] - sum[i - 1]);
	}
	LL res = 0;
	for(int i = 1 ; i < n ; i ++){
		LL id = idx.front();
		idx.pop();
		if(id > n){
			res = id;
		}
		else if(isv[id] == 1){
			res = id;
		}
		else{
			isv[id] = 1;
		}
	}
	LL k = 0;
	int cnt = 0;
	for(int i = 1 ; i <= n ; i++){
		if(isv[i] == 0){
			cnt++;
			k +=i;
		}
	}
	if(cnt == 1){
		cout<<"YES\n";
	}
	else if(k != res || cnt > 2){
		cout<<"NO\n";
	}
	else{
		cout<<"YES\n";
	}
//	cout<

1851E - Nastya and Potions 

        题意:有n种药剂,其中你有p种药剂是免费的,其中一种药剂可以通过其他的药剂混合而成或者通过购买花费金币获得。给定每个药剂的配方,若无配方则只能通过购买获得。求获得每个药剂的最小金币数。

        思路:典型的记忆化搜索题目,dp(i)表示求第i种药剂所花费的最小金币数,cost[i]表示第i种药剂所花费的最小金币数,isv[i]表示是否已经算出了cost[i],用容器e[i]表示合成第i种药剂所需要的药剂。若cost[i]已经求出来了,则标记一下,下次直接返回cost[i]即可。cost[i] = min(cost[i] , \sum_{j = 0}^{e[i].size() - 1} (cost[e[i][j]]))

LL cost[N];
int isv[N];
vectore[N];
LL dp(int n){
	if(isv[n] == 1)
		return cost[n];
	LL co = 0;
	for(int i = 0 ; i < e[n].size() ; i++){
		co += dp(e[n][i]);
	}
	cost[n] = min(cost[n] , co);
	isv[n] = 1;
	return cost[n];
}
void solve() 
{
	int n , p;
	cin>>n>>p;
	for(int i = 1 ; i <= n ; i++){
		cin>>cost[i];
		isv[i] = 0;
		e[i].clear();
	}
	for(int i = 0 ; i < p ; i++){
		int num;
		cin>>num;
		cost[num] = 0;
	}
	for(int i = 1 ; i <= n ; i++){
		int op;
		cin>>op;
		if(op == 0){
			isv[i] = 1;
		}
		else{
			for(int j = 0 ; j < op ; j ++){
				int num;
				cin>>num;
				e[i].pb(num);
			}
		}
	}
	for(int i = 1;  i <= n ; i++){
		cout<

1851F - Lisa and the Martians 

        题意:给定一个整数k,给定n个整数,其中每个数 < 2^k。从中选取两个数和一个任意数x。求小于2*k的(a_{i} \oplus x)\&(a_j \oplus x)的最大值。

         思路:假设(a_{i} \oplus x)\&(a_j \oplus x) = y 。对于每一位来说,若a_{im} =a_{jm},则y_{m} = 1(m为二进制所在位数)。则y = ((1 << k) - 1) \oplus (a_{i} \oplus a_{j})。因此(a_{i} \oplus a_{j})越小越好。求异或最小值用trie树解决(没写出来)。求两数异或值最小,还可以通过排序后求相邻数对异或的最小值。

PII a[N];
int cmp(PII a, PII b){
	return a.first < b.first;
}
void solve ()
{
	int n, k;
	cin >> n >> k;
 
	for (int i = 1; i <= n; i++) {
		cin >> a[i].first;
		a[i].second = i;
	}
	sort (a+1, a + n+1 , cmp);
	int idx,minx=2e9;
	for (int i = 2; i <= n; i++) {
		if (minx > (a[i].first ^ a[i - 1].first)) {
			minx = a[i].first ^ a[i - 1].first;
			idx = i;
		}
	}
	int m = ((1 << k) - 1) ^ a[idx].first;
	cout << a[idx].second << " " << a[idx-1].second << " " << m << endl;
}

你可能感兴趣的:(算法,图论,c++,数据结构)