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