Codeforces Round #697 (Div. 3) 全题解

这次DIV3 ( ~~太卷了~~ )太棒了~~~

A题

题目大意
判断一个整数 n ,是否存在大于 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=0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 3e5 + 5;
const int N=1005;
using namespace std;

int main() {

	int ncase;
	cin >> ncase;
	while(ncase--){
		ll n;
		cin >> n;
		while(n % 2 == 0) n /= 2;
		if(n != 1) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
	
	return 0;
}

B题

题目大意
判断 n 是否存在一对 (x,y)使得 2020 * x + 2021 * y = n

思路
令 a = n / 2020, b = n % 2020, 如果 b 小于等于 a,我们也就可以在 a 个2020,分出 b 个 2020 和剩下的 b 凑成 b 个2021。
如果 b <= a, 就是 yes,否则就是 no

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=0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 3e5 + 5;
const int N=1005;
using namespace std;

int main() {

	int ncase;
	cin >> ncase;
	while(ncase--){
		ll n;
		cin >> n;
		int a = n / 2020;
		int b = n % 2020;
		if(a < b) cout << "NO" << endl;
		else cout << "YES" << endl;
	}
	
	return 0;
}

C题

题目大意
给出 k 对数 (ai, bi),询问有多少对( ai bi ) , ( aj , bj ) 使得ai ! = aj , bi ! = bj

思路
容斥原理
对于 (ai, bi) 满足的 ( aj , bj ) 的个数有:k - num(ai) - num(bi) + num(ai,bi)
统计所有的对数,再除二就OK
注意别爆int

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=0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 3e5 + 5;
const int N=1005;
using namespace std;

int a[maxn];
int b[maxn];
int aa[maxn];
int bb[maxn];

map<pair<int, int>, int> v;

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;
}

int main() {

	int ncase;
	read(ncase);
	while(ncase--){
		ll n, m, k;
		read(n); read(m);read(k);
		for(int i = 1; i <= k; i++) read(a[i]);
		for(int j = 1; j <= k; j++) read(b[j]);
		for(int j = 1; j <= n; j++) aa[j] = 0;
		for(int j = 1; j <= m; j++) bb[j] = 0;
		for(int j = 1; j <= k; j++) aa[a[j]]++;
		for(int j = 1; j <= k; j++) bb[b[j]]++;
		for(int j = 1; j <= k; j++) v[{a[j], b[j]}]++;
		ll res = 0;
		for(int i = 1; i <= k; i++){
			res += 1ll * k - 1ll * aa[a[i]] - 1ll * bb[b[i]] + 1ll * v[{a[i], b[i]}];
		}
		printf("%lld\n", res / 2);
		v.clear();
	}
	
	return 0;
}

D题

题目大意
给出N个物品,每个物品有一个质量和花费,求出在质量大于等于m时的最小花费。
思路
做法 题目数据范围说了花费只会是1或者2,所以我们开两个数组,存1和2的花费
因为在花费相同的情况下,肯定优先选大的质量,所以我们从大到小排序,然后我们去枚举花费1用了多少个,然后二分找出花费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 int INF=0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 2e5 + 5;
const int N=1005;
using namespace std;

ll c[maxn];
ll a[maxn] = {0};	// 存 1 
ll b[maxn] = {0};   // 存 2 

bool cmp(ll x, ll y){
	return x > y;
}

int main() {
	
	int ncase;
	cin >> ncase;
	while(ncase--){
		ll n, m;
		cin >> n >> m;
		for(int i = 1; i <= n; i++) cin >> c[i];
		ll sum = 0, f, cnt1 = 0, cnt2 = 0;
		for(int i = 1; i <= n; i++){
			cin >> f;
			if(f == 1) a[++cnt1] = c[i];
			else b[++cnt2] = c[i];
			sum += c[i];
		}
		
		if(sum < m){
			cout << -1 << endl;
			continue;
		}
		
		sort(a+1, a+1+cnt1, cmp);
		sort(b+1, b+1+cnt2, cmp);
		
		a[0] = b[0] = a[cnt1+1] = b[cnt2+1] = 0;
		for(int i = 1; i <= cnt1; i++) a[i] += a[i-1];
		for(int i = 1; i <= cnt2; i++) b[i] += b[i-1];
		
		int res = INF;
		for(int i = 0; i <= cnt1; i++){
			ll tmp = m - a[i];
			int ind = lower_bound(b + 1, b + 1 + cnt2, tmp) - b;
			if(a[i] + b[ind] >= m) res = min(res, i + ind * 2);
			ind--;
			if(a[i] + b[ind] >= m) res = min(res, i + ind * 2);
		}
		
		if(res == INF) res = -1;
		cout << res << endl;
		
	}
	
	return 0;
}

E题

题目大意
给出 n 个数,长度为 m 的子序列且子序列的sum最大,问这样的子序列有多少个。

思路
组合数

先排序,根据贪心思想,我们一定会选前 m 大的数。
我们设前 m 大的数里有 x 个不同的数构成(eg:1、2、3、3,前 3 大的数由2 和 3 构成,x = 2)。
可以确定,排序后的x个不同的数,在前 x-1 个数一定会全部被选(设有 z 个),在第 x 大的数中选 m - z 个数。
设v[ai] 为 a[i] 的个数,也就是说算一下组合数C(m-z,v[ai] )。

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=0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 3e5 + 5;
const int N=1005;
using namespace std;

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;
}

map<int, ll> v;
ll a[1005];

ll V[2005][2005] = {0};

void init(){
	V[0][0] = V[1][1] = V[1][0] = 1;
	for(int i = 2; i <= 2000; i++){
		V[i][0] = 1;
		for(int j = 1; j <= i; j++){
			V[i][j] = (V[i-1][j-1] + V[i-1][j]) % mod;
		}
	}
}

int main() {
	
	init();	// 预处理组合数
	
	int ncase;
	read(ncase);
	while(ncase--){
		ll n, m;
		read(n); read(m);
		for(int i= 1; i <= n; i++) read(a[i]);
		for(int i= 1; i <= n; i++) v[a[i]]++;
		sort(a+1, a+1+n);
		a[n+1] = 0;
		ll res = 1;
		for(int i = n; m; i--){
			if(a[i] == a[i+1]) continue;
			if(m >= v[a[i]]) m -= v[a[i]];
			else res = V[v[a[i]]][m], m = 0;
		}
		cout << res << endl;
		v.clear();
	}
	
	return 0;
}

F题

题目大意
给出两个 01 矩阵,A 与 B。每次可以对 A 的一行的所有数和 1 进行异或,或者对 A 的一列的所有数和 1 进行异或,询问是否可以通过一系列的操作使得 A 变成 B 。

思路
考虑奇偶性:
如果对一行进行奇数次操作,这一行会发生变化。
如果对一行进行偶数次操作,这一行不会发生变化。(原因: x ^ x = 0,0 ^ x = x)
首先遍历最左一列的数字,若A与B中的不同,则对一整行元素进行异或运算,遍历完之后应该不会有更多行异或的操作,因此,从第二列开始遍历,此时矩阵A与矩阵B在同一列中的元素应该全部相等或者全部相反,若出现矛盾,则矩阵A不能通过变换到达矩阵B。

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=0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 2e5 + 5;
const int N=1005;
using namespace std;

int v[1005][1005] = {0};
int lin[1005] = {0};
int row[1005] = {0};

int main() {
	
	int ncase;
	cin >> ncase;
	while(ncase--){
		int n;
		cin >> n;
		char a[1005];
		for(int i = 1; i <= n; i++){
			cin >> (a+1);
			for(int j = 1; j <= n; j++){
				if(a[j] == '1') v[i][j] ^= 1;
				else v[i][j] ^= 0;
			}
		}
		
		for(int i = 1; i <= n; i++){
			cin >> (a+1);
			for(int j = 1; j <= n; j++){
				if(a[j] == '1') v[i][j] ^= 1;
				else v[i][j] ^= 0;
			}
		}
		
		for(int i = 1; i <= n; i++){
			if(v[i][1]){
				for(int j = 1; j <= n; j++){
					v[i][j] ^= 1;
				} 
			}
		}
		
		int f = 1;
		for(int i = 2; i <= n; i++){
			for(int j = 2; j <= n; j++){
				if(v[1][i] != v[j][i]){
					f = 0;
					break;
				}
			}
			if(f == 0) break;
		}
		
		if(f) cout << "YES" << endl;
		else cout << "NO" << endl;
		chushi(v, 0); chushi(lin, 0); chushi(row, 0);
	}
	
	return 0;
}
 

G题

题目大意
定义一个数组是好的,当前仅当任意两个数 ai 和 aj 都满足 ai % aj = 0 或者 aj % ai = 0 ,问最少删除几个数使得数组变好。

思路
DP
dp[i] 表示以 i 作为最小因子组成的好数组的元素个数。
则:dp[i * j] = max(dp[i * j], dp[i] + v[i*j]); ( j 为 2 到 x, i * x > amax )

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=0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 2e5 + 5;
const int N=1005;
using namespace std;

int v[maxn] = {0};
int dp[maxn] = {0};

int main() {
	
	int ncase;
	cin >> ncase;
	while(ncase--){
		int n;
		cin >> n;
		int num, mx = -1;
		for(int i = 1; i <= n; i++){
			cin >> num;
			v[num]++;
			mx = max(mx, num);
		}
		
		for(int i = 1; i <= mx; i++) dp[i] = v[i];
		
		for(int i = 1; i <= mx; i++){
			if(v[i] == 0) continue;
			for(int j = 2; j * i <= mx; j++){
				if(v[i * j] == 0) continue;
				dp[i * j] = max(dp[i * j], dp[i] + v[i*j]);
			}
		}
		
		int res = -1;
		for(int i = 1; i <= mx; i++) res = max(res, dp[i]);
		cout << n - res << endl;
		chushi(dp, 0); chushi(v, 0);
	}
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值