Codeforces Round #694 (Div. 1 + Div2)

ABC略

D(d1B)

显然,对于两个数x,y对其质因数分解后得到的质因数次数的奇偶性相同,那么就满足题意,然后又可以发现在第一秒过去之后,个数为偶数的满足题意的数的质因数的次数会变成全偶.

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define int long long
#define PII pair<int, int>
using namespace std;
const int N = 1e6 + 10;
int n, q, a[N], primes[N], cnt;
int vis[N];
map<int, int> cc;
void get_prime(int n) {
	for(int i = 2;i <= n;i ++) {
    	if(!vis[i]) primes[++cnt] = i;
    	for(int j = 1;j <= cnt && i * primes[j] <= n; ++ j) {
        	vis[i * primes[j]] = 1;
            if(i % primes[j] == 0) break;
    	}
    }
}
void solve() {
	cin >> n;
	cc.clear();
	for (int i = 1; i <= n; ++i) {
		cin >> a[i];
		int now = 1;
		for (int j = 1; j <= cnt && primes[j] <= a[i] / primes[j]; ++j) {
			int c = 0;
			while (a[i] % primes[j] == 0) ++c, a[i] /= primes[j];
			if (c % 2 == 1) now *= primes[j];
		}
		if (a[i] > 1) now *= a[i];
		++cc[now];
	}
	int ans0 = 1, ans1 = 1;
	for (auto [x, y] : cc) {
		ans0 = max(ans0, y);
	}
	int tt = 0;
	for (auto &[x, y] : cc) {
		if (y % 2 == 0 && x != 1) {
			tt += y;
		}
	}
	cc[1] += tt;
	for (auto [x, y] : cc) {
		if (x == 1 || y % 2 == 1) {
			ans1 = max(ans1, y);
		}
	}
	int q;
	cin >> q;
	while (q--) {
		int x;
		cin >> x;
		if (x == 0) cout << ans0 << "\n";
		else cout << ans1 << "\n";
	}
}
signed main() {
	IOS;
	get_prime(N - 10);
	int T = 1;
	cin >> T;
	while (T--) solve();
}

E(d1C)打表+分块

 打表可得到以下规律,

1.叛徒的卡片不会改变,一直为k

2.以叛徒为中心,每秒左边会多出一个小于k的,每秒右边会多出一个大于k的人

假设i秒过去了,

 中间蓝色的点就是叛徒,牌数为k,其他没改变的人为红色,也为k.

我们可以先过sqrt(n)秒,然后图中蓝色线段的长度就为2√n + 1,其余的长度为n - (2√n + 1),然后我们从1号点开始询问,每次跳跃的步长为sqrt(n),直到询问道一个牌数不为k的人,此时肯定进入了蓝色线段内(并且当前的人不是叛徒),然后乱搞就能问出来了,均摊复杂度是O(√n)级别的.至于为什么一定能跳到蓝色线段,留给读者自证.

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define int long long
#define PII pair<int, int>
using namespace std;
int n, k;
int ask(int x) {
	cout << "? " << x + 1 << endl;
	int res;
	cin >> res;
	return res;
}
signed main() {
	IOS;
	cin >> n >> k;
	int B = sqrt(n) - 1;
	for (int i = 0; i <= B; ++i) ask(i);
	int now = 0, val = ask(now);
	while (val == k) {
		now = (now + B) % n;
		val = ask(now);
	}
	if (val < k) {
		while (ask((now + B) % n) < k) now = (now + B) % n;
		while (ask((now + 1) % n) < k) now = (now + 1) % n;
		now = (now + 1) % n;
	}else {
		while (ask((now - B + n) % n) > k) now = (now - B + n) % n;
		while (ask((now - 1 + n) % n) > k) now = (now - 1 + n) % n;
		now = (now - 1 + n) % n;
	}
	cout << "! " << now + 1 << endl;
}

F(d1D)

题意: 给定一张n个节点m条边的无向图,要求对图中节点进行黑白染色,需要满足:每条边的端点至多一个黑色的节点,如果两端都是白色的节点,那么这条边会被删除.

首先想到先跑一棵生成树,然后发现贪心地构造即可,即从根部往下,对于每个点,如果周围没有黑点,那么这个点染黑,否则染白,除非图不联通,否则一定有解(不放心的话可以特判一下)

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define int long long
#define PII pair<int, int>
using namespace std;
const int N = 2e6 + 10;
int n, m, a[N], vis[N], ans;
vector<int> g[N];
void dfs(int x) {
	vis[x] = 1;
	bool ok = 1;
	for (int y : g[x]) {
		if (vis[y] && a[y] == 1) ok = 0; 
	}
	if (ok) a[x] = 1, ans += 1;
	else a[x] = 0;
	for (int y : g[x]) {
		if (!vis[y]) dfs(y);
	}
}
void solve() {
	cin >> n >> m;
	ans = 0;
	for (int i = 1; i <= n; ++i) {
		a[i] = -1, vis[i] = 0;
		g[i].clear();
	}
	for (int i = 1; i <= m; ++i) {
		int x, y;
		cin >> x >> y;
		g[x].emplace_back(y);
		g[y].emplace_back(x);
	}
	dfs(1);
	for (int i = 1; i <= n; ++i) {
		if (a[i] == -1) return cout << "NO\n", void(0);
	}
	cout << "YES\n";
	cout << ans << "\n";
	for (int i = 1; i <= n; ++i) {
		if (a[i]) cout << i << " ";
	}
	cout << "\n";
}
signed main() {
	IOS;
	int T = 1;
	cin >> T;
	while (T--) solve();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值