Codeforces Round 1017 (Div. 4)题解ABCDEFGH

出去交流了一阵子  回来打了个篮球杯  准备慢慢备战国赛和上半年CCPC

Problem - A - Codeforces

思路:直接模拟

// Code Start Here	
	int t;
	cin >> t;
	while(t--){
		string a , b , c;
		cin >> a >> b >> c;
		cout << a[0] << b[0] << c[0] << endl;
	}

Problem - B - Codeforces

思路:中间分别往左右蔓延

// Code Start Here	
	int t;
	cin >> t;
	while(t--){
		int n , m , l , r;
		cin >> n >> m >> l >> r;
		int right = min(m , r);
		int left = right - m;
		cout << left << " " << right <<endl;
	}
	return 0;	

Problem - C - Codeforces

思路:直接模拟,题目说明了G与P的关系,模拟一遍看谁没出现即可

// Code Start Here	
	int t;
	cin >> t;
	while(t--){
		int n;
		cin >> n;
		vvi g(n+1,vi(n+1));
		for(int i = 1;i<=n;i++){
			for(int j = 1;j<=n;j++){
				cin >> g[i][j];
			}
		}
		vi p(2*n);
		for(int i = 1;i<=n;i++){
			for(int j = 1;j<=n;j++){
				p[i+j-1]=g[i][j];
			}
		}
		int ans = 0;
		for(int i = 1;i<=2* n;i++)ans^= i;
		for(int i : p)ans ^= i;
		for(int i : p){
			if(i == 0)cout << ans << " ";
			else cout << i << " ";
		}
		cout << endl;
	}
	return 0;	

Problem - D - Codeforces

这个题的名字很好玩

思路:观察到一个结论,我们注意到对于一个长度为x的连续的相同L或者R,可以允许的区间长度一定是 x ~ 2x,所以对应的,如果两端区间对应,那么长度的可能一定是有交集的,双指针扫一遍即可

// Code Start Here	
	int t;
	cin >> t;
	while(t--){
		string a, b; cin >> a >> b;
		vector<pair<char, int>> A, B;
		int cnt = 1;
		char buk = a[0];
		for (int i = 0; i < a.size() - 1; ++i) {
			if (a[i] != a[i + 1]) {
				A.push_back({buk, cnt});
				buk = a[i + 1];
				cnt = 1;
			} else {
				cnt++;
			}
		}
		A.push_back({buk, cnt});
		cnt = 1;
		buk = b[0];
		for (int i = 0; i < b.size() - 1; ++i) {
			if (b[i] != b[i + 1]) {
				B.push_back({buk, cnt});
				buk = b[i + 1];
				cnt = 1;
			} else {
				cnt++;
			}
		}   
		B.push_back({buk, cnt});
		bool f = true;
		if (A.size() != B.size()) f = false;
		for (int i = 0; i < A.size(); ++i) {
			if (A[i].first != B[i].first || A[i].second > B[i].second || 2 * A[i].second < B[i].second) {
				f = false;
			}
		}
		if(f)cout << "YES" << endl;
		else cout <<"NO" << endl;
	}
	return 0;	

Problem - E - Codeforces

思路:观察数据范围 2^30,又是位运算,考虑按位贪心。

观察到题目要求求1 ~ n的k使得异或之和最大,根据位运算的性质,可以记录一下该位上1/0的个数,然后思考怎么使得和最大,答案显而易见肯定是能弄出来尽量多的1的更大,预处理后贪心即可

#define int long long了没有?

/ Code Start Here	
	int t;
	cin >> t;
	while(t--){
		int n; cin >> n;
		vector<int> a(n);
		for(int i = 0;i<n;i++)cin >> a[i];
		
		vvi v(n, vi(30));
		vector<int> cnt0(30,0), cnt1(30,0);
		for (int i = 0; i < n; ++i) {
			for (int j = 0; j < 30; ++j) {
				v[i][j] = (((a[i]) >> j) & 1);
				if (v[i][j] == 1) {
					cnt1[j]++;
				} else {
					cnt0[j]++;
				}
			}
		}
		int ans = 0;
		for (int i = 0; i < n; ++i) {
			int now = 0;
			for (int j = 0; j < 30; ++j) {
				if ((a[i] >> j) & 1) {
					now += (cnt0[j]) * (1 << j);
				} else {
					now += (cnt1[j]) * (1 << j);
				}
			}
			ans = max(ans, now);
		}
		cout << ans << endl;
	}
	return 0;

Problem - F - Codeforces

思路:我们发现可以直接输出1-k  但是样例1的2 2 2,即m,k为倍数关系,明显会导致上下相等,这个时候直接移位一位即可

// Code Start Here	
	int t;
	cin >> t;
	while(t--){
		int n , m , k;
		cin >> n >> m >> k;
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= m; j++) {
				int now = (i - 1) * m + j;
				if (i % 2 == 1 && m % k == 0) {
					now += 1;
				}
				int tmp;
				if (now % k == 0) {
					tmp = k;
				} else {
					tmp = now % k;
				}
				cout << tmp << ' ';	
			}
			cout << endl;
		}
	}
	return 0;

Problem - G - Codeforces

思路:观察题目,反转,前后移项,末尾添加,是deque。

思考元素乘以下标的和怎么快速改变

化简一下式子就有

操作1:ans + sum - a_n * n

操作2:sum *(n+1) - ans

操作3:+ add

记得记录一下反转情况

// Code Start Here	
	int t;
	cin >> t;
	while(t--){
		int q;
		cin >> q;
		deque<int> dq;
		bool rev = false;
		int sum = 0, now = 0;
		int n = 0;
		while(q--){
			int s;
			cin >> s;
			if(s == 1){
				int last;
				if(!rev){
					last = dq.back();
					dq.pop_back();
					dq.push_front(last);
				} else {
					last = dq.front();
					dq.pop_front();
					dq.push_back(last);
				}
				now += sum - n * last;
				cout << now << endl;
			} else if(s == 2){
				now = (n + 1) * sum - now;
				rev = !rev;
				cout << now << endl;
			} else {
				int k;
				cin >> k;
				n++;
				sum += k;
				now += k * n;
				if(!rev)
					dq.push_back(k);
				else
					dq.push_front(k);
				cout << now << endl;
			}
		}
	}
	return 0;

Problem - H - Codeforces

比较有思维量的一个题

题意:

你有一个整数数组 a,每个查询给出 k, l, r:初始值是 k遍历从 a[l] 到 a[r] 的元素,对 k 不断执行找到下一个位置 i,使得 a[i] 是 k 的约数在 i 到当前位置的范围,贡献为 区间长度 × 当前 k然后令 k /= a[i],重复这个过程最后,剩余未处理的区间长度 × 最终 k,加到结果中目标是输出所有查询的结果。

思路:

我们先预处理所有数的因数用于后续快速查找 k 的约数,然后建立数值到下标的映射,目的是为了查询某个值为x的数在数组里面的所有出现位置,方便通过二分找下一个满足条件的位置。然后不断寻找 k 的因数在 [l, r] 区间的最左位置即可

模拟+数论

// Code Start Here	
	const int N = 2e5+10;
	vvi div(N);
	for (int i = 2; i <= N; i++) {
		for (int j = i; j <= N; j += i) {
			div[j].push_back(i);
		}
	}
	int t;
	cin >> t;
	while(t--){
		int n, q;
		cin >> n >> q;	
		vi a(n);
		for(int i = 0;i<n;i++)cin >> a[i];
		map<int, vi> mp;
		for (int i = 0; i < n; i++) mp[a[i]].push_back(i);
		while (q--) {
			int k, l, r;
			cin >> k >> l >> r;
			l--;
			r--;
			int ans = 0;
			int last = l;
			while(true) {
				if (k == 1) break;
				int idx = -1;
				for (auto i : div[k]) {
					int near = lower_bound(all(mp[i]), l) - mp[i].begin();
					if (near == mp[i].size()) continue;
					int now = mp[i][near];
					if (now > r) continue;
					if (idx == -1 || now < idx) {
						idx = now;
					}
				}
				if (idx == -1) break;
				ans += (idx - last) * k;
				while (k % a[idx] == 0) k /= a[idx];
				last = idx;
			}
			ans += (r - last + 1) * k;
			cout << ans << endl;
		}
	}
	return 0;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值