Codeforces Round #714 (Div. 2)(A-D)

这篇博客探讨了四个算法问题,包括寻找数组中的波峰数量、满足特定条件的排列计数、数字加一操作后的长度计算以及最大公约数与最小生成树的关联。通过分析题目要求,提出了高效的解决方案,并提供了C++代码实现。这些算法涉及数组操作、位运算、递归和图论等概念,对于提升编程能力和理解数据结构有很好的帮助。
摘要由CSDN通过智能技术生成

A. Array and Peaks

题目大意
询问是否存在一个长度为 n 的排列有 k 个波峰(同时满足 ai > ai-1 和 ai > ai+1 的 i 就是一个波峰)

思路
考虑一个长度为 n 的排列存在最多波峰的情况,即:1、n、2、n-1、3、n-2 …
可以发现,最多波峰数等于 (n-1) / 2 向下取整。
每次询问,如果 k <= (n-1) / 2 向下取整,那么我们依次输出 k 个波峰以后,在顺序输出剩下的数即可。

AC代码

#include <bits/stdc++.h>
#include <vector>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>                                                                   
#include <set>
#include <stack>
#define ll long long
#define chushi(a, b) memset(a, b, sizeof(a))
#define endl "\n"
const double eps = 1e-8;
const ll INF = 9223372036854775807;
const int mod = 1e9+7;
const int maxn = 2e5 + 5;
using namespace std;

int main(){
	
	int ncase;
	cin >> ncase;
	while(ncase--){
		int n, k;
		cin >> n >> k;
		if(k > (n-1)/2) cout << "-1" << endl;
		else{
			cout << 1 << " ";
			for(int i = 1; i <= k; i++) cout << n+1-i << " " << i+1 << " ";
			for(int i = 1+k+1; i <= n-k; i++) cout << i << " ";
			cout << endl;
		}
	}
	
	return 0;
}

B. AND Sequences

题目大意
给出一个有 n 个元素的数组 a,求:对于所有的 i ,都满足 a1 & a2 & … & ai = ai+1 & ai+2 &…& an 的排列的个数

思路
观察题目要求:
当 i = 1 时,有 a1 = a2 & a3 & a4 & a5 & … &an-1 & an
当 i = n 时,有 a1 & a2 & a3 & a4 & a5 & … &an-1 = an
由上我们可以确定,对于一个满足的排列方式一定有 a1 = an
对于 & 运算的特点,1 & 1 = 1,其他情况均为 0。
也就是说,我们对 n 个数进行连续的 & 运算的结果 tmp 应该放在 a1 或者 an 的位置。
所以说,如果数字 a 中有 cnt 个数等于 tmp ,当 cnt >= 2 and 对于所有的 ai & tmp == tmp 时,这个数组才满足题意的排列,排列的总数为: cnt * (cnt-1) * ((n-2)!)

AC代码

#include <bits/stdc++.h>
#include <vector>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>                                                                   
#include <set>
#include <stack>
#define ll long long
#define chushi(a, b) memset(a, b, sizeof(a))
#define endl "\n"
const double eps = 1e-8;
const ll INF = 9223372036854775807;
const ll mod = 1e9+7;
const int maxn = 2e5 + 5;
using namespace std;

ll a[maxn];

int main(){
	
	int ncase;
	cin >> ncase;
	while(ncase--){
		ll n;
		cin >> n;
		for(int i = 1; i <= n; i++) cin >> a[i];

		ll tmp = a[1];
		for(int i = 2; i <= n; i++) tmp &= a[i];
		ll f = 1, cnt = 0;
		for(int i = 1; i <= n; i++){
			if((a[i] & tmp) != tmp) f = 0;
			if(a[i] == tmp) cnt++;
		}
		if(f == 0 || cnt < 2){
			cout << 0 << endl;
			continue;
		}
		ll res = 0;
		res = cnt * (cnt-1) % mod;
		for(ll i = 1; i <= n-2; i++) res = res * i % mod;
		cout << res << endl;
	}
	
	return 0;
}

C. Add One

题目大意
给出一个数 n,对它进行 d 次操作,求出操作过后这个数的长度。
这个操作为:对于一个数 x,对 x 的每个数位都 +1。eg:5 -> 6, 123 -> 234, 129 -> 2310。

思路
我们先预处理对 0 进行 z 次操作后得到的数的长度, 再预处理对 0 进行 d 次操作后得到的数的长度。
我们把一个数 num 拆开来看,对于一个数位 x 来说,它需要 10 - x 次操作变成 10。
如果 10 - x 大于 d ,则 d 次操作不好让改变长度。
如果 10 - x 小于等于 d,也就是说可以对 10 进行 d - (10-x) 次操作,也就是说分别对 0 和 1 进行 d - (10-x) 次操作。
对所有数位进行这样的计算即可。

AC代码

#include <bits/stdc++.h>
#include <vector>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>                                                                   
#include <set>
#include <stack>
#define ll long long
#define chushi(a, b) memset(a, b, sizeof(a))
#define endl "\n"
const double eps = 1e-8;
const ll INF = 9223372036854775807;
const ll mod = 1e9+7;
const int maxn = 2e5 + 5;
using namespace std;

ll v[2][maxn] = {0};

ll sum[maxn] = {0};

template<class T>inline void read(T &res)
{
    char c;T flag=1;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
    while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}

void init() {
	for(int i = 0; i < 10; i++) v[0][i] = 1;
	for(int i = 0; i < 9; i++) v[1][i] = 1;
    v[1][9] = 2;
    for(int i = 10; i < maxn; i++) {
        v[0][i] = (v[0][i - 10] % mod + v[1][i - 10] % mod) % mod;
        v[1][i] = (v[0][i - 9] % mod + v[1][i - 9] % mod) % mod;
    }
    for(int i = 0; i < maxn; i++) sum[i] = (v[0][i] + v[1][i]) % mod;
}

int main(){
	
	init();
	
	int ncase;
	read(ncase);
	while(ncase--){
		ll n, m;
		read(n); read(m);
		ll res = 0;
		while(n){
			ll tmp = 10 - (n % 10);
			if(m < tmp) res++;
			else{
				res += sum[m - tmp];
				res %= mod;
			}
			n /= 10;
		}
		printf("%lld\n", res);
	}
	
	return 0;
}

D. GCD and MST

思路

这是一个披着图论的皮的思维题,按照题意去找,对于每个点都选择花费最小的连接方式即可。

AC代码

#include <iostream>
#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int maxn = 2e5 + 5;
ll a[maxn];
bool f[maxn] = {false};
vector<pair<ll, int> > v;

int main(int argc, char** argv) {
	
	int ncase;
	cin >> ncase;
	while(ncase--){
		ll n, p;
		cin >> n >> p;
		for(int i = 1; i <= n; i++) cin >> a[i];
		pair<ll, int> tmp;
		for(int i = 1; i <= n; i++){
			tmp.second = i;
			tmp.first = a[i];
			v.push_back(tmp);
		}
		
		sort(v.begin(), v.end());
		
		ll res = n * p - p;
		for(int i = 0; i < n; i++){
			if(v[i].first >= p) break;
			if(f[v[i].second]) continue;
			int ind = v[i].second;
			for(int j = ind-1; j > 0; j--){
				if(a[j] % a[ind] != 0) break;
				res = res - p + a[ind];
				if(f[j]) break;
				f[j] = true; 
			}
			for(int j = ind+1; j <= n; j++){
				if(a[j] % a[ind] != 0) break;
				res = res - p + a[ind];
				if(f[j]) break;
				f[j] = true; 
			}
			f[ind] = true;
		}
		
		cout << res << endl;
		
		for(int i = 1; i <= n; i++) f[i] = false;
		v.clear();
	}
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值