算法思维训练之思维题和容斥原理实战演练 (2月8日)

105 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 8 天,点击查看活动详情

Odd Divisor

image.png

题意:检查n是否有一个大于1的奇数因子

题解:要想有奇数因子,那么这个数的因子,至少包含一个奇数的质数,那么只需要把质数中的偶数剔除就可以了,质数里面只有一个偶数,就是2,那么剔除2,所以2的幂没有奇数因子,其他都有。

signed main() {
	int t;
        scanf("%d", &t);
	while (t--) {
                int n;
		scanf("%d", &n);
		if (n > 0 && (n & (n - 1) == 0)) printf("NO\n");
		else printf("YES\n");
	}
	return 0;
}

New Year's Number

image.png 题意:判断这个数能不能由2020和2021组成。

题解:

  1. 一个尾数是1,一个尾数是0,那么n / 2020就可以求出最多能取多少个2020

  2. 再计算n % 2020,就是计算需要多少个1

  3. 如果需要1的个数 <= 最多能取的2020个数,那么把需要1的个数,记为需要2021的个数,

  4. 反之剩余的数一定比2020小,所以不存在x,y(x,y为大于0的整数)使之满足下式:x×2020+y×2021==nx × 2020 + y × 2021 == n,则输出NO。

综上所述:分类讨论即可

① if (n / 2020 >= n % 2020) printf("YES\n");

② else printf("NO\n");

signed main()
{
	scanf("%d", &t);
	while (t--) {
		scanf("%d", &n);
		if (n / 2020 >= n % 2020) printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}

Ball In Berland(容斥思想)

image.png

题意:选出两组组合,要求不能有一个人同时在两组,求可行的方案数。

题解:

题目给出三个数,a, b, k (a:男生的个数,b:女生的个数,k:男女配对好了的个数)

第二行,是男生,第三行是女生,上下配对

从这些对数里面挑出两对,一个男生不能出现两次,所以每个男生的次数 == 1,每个女生的次数也 == 1;

先分别统计男生和女生在配对数中出现的次数,从头到尾遍历一遍,

ans+=总共的方案(k-i)-当前男生出现过的次数-当前女生出现过的次数+当前男生和当前女生同时出现的次数(容斥定理)

const int N = 200010;
pair<int, int> p[N];
map<pair<int, int>, int> q;
int m[N], n[N];
signed main() {
        int t;
	scanf("%d", &t);
	while (t--) {
		int a, b, k;
                scanf("%d%d%d", &a, &b, &k);
		mem(m, 0);//记得清零
		mem(n, 0);
		q.clear();
		for (int i = 1; i <= k; i++) {
			p[i].first = read();
			m[p[i].first]++;
		}
		
		for (int i = 1; i <= k; i++) {
			p[i].second = read();
			n[p[i].second]++;
		} 
		
		for (int i = 1; i <= k; i++) q[{p[i].first, p[i].second}]++;//统计一下两者同时出现的数量
		int ans = 0;
		for (int i = 1; i <= k; i++) {
			q[{p[i].first, p[i].second}]--;//先减去自己这一次,避免重复
                        m[p[i].first]--;
                        n[p[i].second]--;
			ans += k - i - m[p[i].first] - n[p[i].second] + q[{p[i].first, p[i].second}];//总的(k - i) - p[i].first 出现过的次数,- p[i].second 出现过的次数 + p[i].first 和 p[i].second 同时出现的次数,防止减多了。
		}
		printf("%lld\n", ans);
	}
	return 0;
}