Codeforces Round #697 (Div. 3)

A. Odd Divisor

题目链接

题目大意

给定一个整数 n,问是否存在大于 1 的质因子。

分析

只要判断是否为 2 的整数次幂就可以了,如果是就输出 YES,否则,输出 NO。

#include<bits/stdc++.h>
using namespace std;

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

B. New Year’s Number

题目链接

题目大意

给定一个整数 n, 问是否能由若干个 2020 和若干个 2021 组成。

分析

令 a = n / 2020,b = n % 2020,
若 a >= b,则输出 YES,否则输出 NO。

#include<bits/stdc++.h>
using namespace std;

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

C. Ball in Berland

题目链接

题目大意

有 a 个男生和 b 个女生,同时还有 k 对关系 (x,y),表示第 x 位男生可以和第 y 位女生跳舞,现在需要你从这 k 对关系中找出互不干扰的两对,即对于找出的两对 (x1,y1) 和 (x2,y2),需要满足 x1 != x2,y1 != y2,问方案数有多少种。

分析

遍历每条边 (x,y),减去第 x 位男生可以配对的女生数和第 y 位女生可以配对的男生数,而这时 (x,y)也被减了两次,所以还要加上 1,最后再除以 2 就可以得到答案了。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int t, a, b, k, men[maxn], women[maxn];

int main()
{
	cin >> t;
	while(t--){
		memset(men, 0, sizeof(men));
		memset(women, 0, sizeof(women));
		map<int, int> mp1, mp2;
		cin >> a >> b >> k;
		for(int i = 1; i <= k; i++){
			cin >> men[i];
			mp1[men[i]]++;
		}
		for(int i = 1; i <= k; i++){
			cin >> women[i];
			mp2[women[i]]++;
		}
		long long ans = 0;
		for(int i = 1; i <= k; i++)
			ans += k - mp1[men[i]] - mp2[women[i]] + 1;
		cout << ans / 2 << endl;
	}
	return 0;
}

D. Cleaning the Phone

题目链接

题目大意

给定 n 个物品,并给出每个物品的质量和花费,问在质量大于等于 m 时的最小花费。

分析

因为 bi 只有 1 和 2 两种取值,所以我们可以先将 bi 等于 1 时对应的 ai 放入 f1 数组中,而把 bi 等于 2 时对应的 ai 放入 f2 数组中,然后将 f1,f2 从大到小排序,同时还需对 f2 求前缀和并存入 pre 数组中,这时,我们只需要枚举 f1,假设此时已经有的总质量为 sum,而我们还需要的质量为 m - sum,因此我们就可以通过二分找到在 pre 数组中第一个大于等于 m - sum 的位置,而这个位置就是我们需要选出的个数,然后更新答案就可以了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
const int inf = 0x3f3f3f3f;
int t, m, n;
ll a[maxn], b[maxn], f1[maxn], f2[maxn], pre[maxn];

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

int main()
{
	cin >> t;
	while(t--){
		cin >> n >> m;
		for(int i = 1; i <= n; i++) cin >> a[i];
		for(int i = 1; i <= n; i++) cin >> b[i];
		int cnt1 = 0, cnt2 = 0;
		for(int i = 1; i <= n; i++){
			if(b[i] == 1) f1[++cnt1] = a[i];
			else f2[++cnt2] = a[i];
		}
		sort(f1 + 1, f1 + cnt1 + 1, cmp);
		sort(f2 + 1, f2 + cnt2 + 1, cmp);
		pre[0] = 0;
		for(int i = 1; i <= cnt2; i++)
			pre[i] = pre[i-1] + f2[i];
		int ans = inf, sum = 0;
		for(int i = 1; i <= cnt1; i++){
			sum += f1[i];
			if(sum >= m){
				ans = min(ans, i);
				break;
			}
			int index = lower_bound(pre + 1, pre + cnt2 + 1, m - sum) - pre;
			if(index == cnt2 + 1) continue;
			else ans = min(ans, i + index * 2);
		}
		int index = lower_bound(pre + 1, pre + cnt2 + 1, m) - pre;
		if(index != cnt2 + 1) ans = min(ans, index * 2);
		if(ans == inf) cout << -1 << endl;
		else cout << ans << endl;
	}
	return 0;
}

E. Advertising Agency

题目链接

题目大意

设长度为 k 的最大子序列和为 max,问长度为 k 的子序列和等于 max 的个数。

分析

贪心选择 k 个 a 最大的代理,假设最后一个入选的代理的追随人数为 target,在入选的代理中和 target 相同的有 cnt 个,而在所有代理中与 target 相同的有 sum 个,则我们需要求的选法数就是组合数 C s u m c n t C_{sum}^{cnt} Csumcnt,因为这题数据范围比较小,可以直接用杨辉三角来递推组合数。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 5;
const int mod = 1e9 + 7;
int a[maxn], c[maxn][maxn];

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

int main()
{
	init();
	int t;
	cin >> t;
	while(t--){
		int n, k;
		cin >> n >> k;
		for(int i = 1; i <= n; i++) cin >> a[i];
		sort(a + 1, a + n + 1);
		int sum = 0, cnt  = 0;
		int target = a[n-k+1];
		for(int i = 1; i <= n; i++){
			if(a[i] == target){
				sum++;
				if(i >= n - k + 1)
					cnt++;
			}
		}
		cout << c[sum][cnt] << endl;
	}
	return 0;
}

F. Unusual Matrix

题目链接

题目大意

给定两个 n * n 的 01 矩阵 a 和 b,每次可以选出矩阵的一行或者一列进行异或 1 的操作,问是否可以通过一系列的操作使得 a 变成 b。

分析

我们可以从 (i,j) 操作的关联性进行考虑,当对 (i,j) 操作时,(1,j) 和 (i,1) 的值会改变,而这两个的值也可以通过 (1,1) 再改回去,所以可以把这四个当成是一个关联组,只有全一样或是全不一样时,才是可以的。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 5;
int t, n, a[maxn][maxn];
string s;

int main()
{
	cin >> t;
	while(t--){
		cin >> n;
		for(int i = 1; i <= n; i++){
			cin >> s;
			for(int j = 1; j <= n; j++)
				a[i][j] = s[j-1] - '0';
		}
		getchar();
		for(int i = 1; i <= n; i++){
			cin >> s;
			for(int j = 1; j <= n; j++){
				a[i][j] = a[i][j] ^ (s[j-1] - '0');
			}
		}	
		int flag = 0;
		for(int i = 2; i <= n; i++)
			for(int j = 2; j <= n; j++)
				if(a[1][1] ^ a[1][j] ^ a[i][1] ^ a[i][j])
					flag = 1;
		if(flag) cout << "NO" << endl;
		else cout << "YES" << endl;
	}
	return 0;
}

G. Strange Beauty

题目链接

题目大意

定义一个数组 a 是好的,当且仅当对于任意一对 i,j,在 i ≠ j 的前提下如果有 ai | aj 或者 aj | ai,问至少删除几个数可以使得数组变好。

分析

定义 dp[x] 为最大元素是 x,满足条件的最大集合的元素个数。这样我们就可以得到状态转移方程:dp[j] = max(dp[j], dp[i] + j 的数量),然后更新答案就可以了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
int t, n;
ll a[maxn], dp[maxn], mp[maxn];

int main()
{
	scanf("%d", &t);
	while(t--){
		memset(dp, 0, sizeof(dp));
		memset(mp, 0, sizeof(mp));
		scanf("%d", &n);
		for(int i = 1; i <= n; i++){
			scanf("%d", &a[i]);
			mp[a[i]]++;
		}
		ll mx = 0;
		dp[1] = mp[1];
		for(int i = 1; i < maxn; i++){
			mx = max(mx, dp[i]);
			for(int j = i + i; j < maxn; j += i)
				dp[j] = max(dp[j], dp[i] + mp[j]);
		}
		printf("%d\n", n - mx);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值