羊蹄
cf104679E:埃式筛法+前缀和
前置知识:筛法
问题:对于节点为 1..N,若两个数有公共质因子(gcd(a, b) > 1)则在它们之间连一条无向边。问哪些点与 2 不连通?
数x与其最小质因子p连通(p ↔ x),当其与2不连通时,可以找到一中间点(同时包含2和p两个质因子(2 ↔ 2p ↔ p)) 则有:2 ↔ 2p ↔ p ↔ x
所以当2p<N即连通(p > N/2,则2p > N)
p为最小质因子, x = p * q(p <= q), 显然p^2 <= x, 若存在p > N/2,则相应的p^2 > (N/2)^2, 除p自身(质数)还在范围内, 都超出范围
对于N/2,N区间,p>N/2只有的质因子本身符合,会被留下,而其余会被p<N/2筛掉
发现:
-
能连到 2 的数:存在质因子 p ≤ N/2;
-
不能连到 2 的数:所有质因子都 > N/2;
即求(N/2, N] 的质数个数,以及N较小时的特殊讨论
点击查看代码
int main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int M = 1e7;
vector<int> is_prime(M + 1, 1);
is_prime[0] = 0, is_prime[1] = 0;
for (int i = 2; i <= M; i ++) {
if (is_prime[i]) {
for (int j = i * 2; j <= M; j += i) {
is_prime[j] = 0;
}
}
}
for (int i = 1; i <= M; i ++) {
is_prime[i] += is_prime[i - 1];
}
int t;
cin >> t;
while (t --) {
int n;
cin >> n;
if (n <= 3) cout << n - 2 << '\n';
else cout << is_prime[n] - is_prime[n / 2] << '\n';
}
return 0;
}
cf104679F:位运算构造
前置知识:#算数基本定律
对于最终值,所有数的二进制位都只能是a的子集(包含b),OR操作取allx的子集,算出的XOR结果和b计算差别。
取奇数个1时XOR取1,但a取0时明显有0个1(即b位上的那个特殊1无法改动,所以b也为a子集)
XOR差别也一定也是a的子集,删去差别对应的(子集中)那个数,再检查或和是否满足条件即可(因为异或和已经满足条件了)
差异diff:
x(a的XOR和) ^ b = k(k属于集合a),求出的k即差异
点击查看代码
int main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while (t --) {
int a, b;
cin >> a >> b;
if ((a | b) != a) cout << -1 << '\n';//b应为a子集
else if ((a & -a) == a && b == 0 && a) {//a为2的幂且想让b == 0时,无解
cout << -1 << '\n';
}
else {
vector<int> ans;
int xor_val = b;
for (int i = 0; i <= a; i ++) {
if ((i & a) == i) {//i为a子集
ans.emplace_back(i);
xor_val ^= i;//最终为b ^ all子集
}
}
int ans_len = ans.size();
if (!xor_val) xor_val = -1;//取0时满足,标记为-1
else ans_len --;//否则需要删除一个数,个数-1
cout << ans_len << '\n';
for (auto &x: ans) {
if(x != xor_val) {//输出其余留下的数
cout << x << ' ';
}
cout << '\n';
}
}
}
return 0;
}
特判掉a为2的幂,且b = 0情况(无解)
其中只有 2 的幂才会满足它自己与其相反数 -a 相与等于自己,即 a 只有一位二进制 1,b == 0想让 XOR 的结果为 0(且判断a,排除a=0的情况)
发现有4=(100),子集为{0, 4},想让 OR = a (即 4),必须选上 4,但选上 4 时,XOR ≠ 0;
如果不选 4,OR 就变成 0 ≠ 4→ ❌ 所以完全无解。
cf104328D:树上DP
C++14[lambda自递归]:lambda自递归
若合数x能整除all路径上点,则x的质因子也必然可以,只需要对那些质数p(p可整除的节点数>N/2)的方案去做判断
此时对树上节点进行染色分为两类:
- p 整除的节点标记为白色
- 其余为黑色
问题变为是否存在一条长为N/2的路径:维护每个点往下的最长的白色路径长度,看能否凑出长度超过N/2的路径即可
点击查看代码
int main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int M = 1e7;
vector<int> prime_factor(M + 1);
iota(prime_factor.begin(), prime_factor.end(), 0);
for (int i = 2; i <= M; i ++) {
if (prime_factor[i] == i) {
for (int j = i; j <= M; j += i) {
prime_factor[j] = i;
}
}
}
int n;
cin >> n;
vector<int> nums(n);
for (auto &x: nums) cin >> x;
vector<vector<int>> path(n);
for (int i = 0; i < n - 1; i ++) {
int u, v;
cin >> u >> v;
u --, v --;
path[u].emplace_back(v);
path[v].emplace_back(u);
}
vector<int> cnt(M + 1, 0);
for (auto &x: nums) {
int vx = x;
while (vx > 1) {
int p = prime_factor[vx];
cnt[p] ++;
while (vx % p == 0) vx /= p;
}
}
int to_check, max_len;
vector<int> dp(n);
auto dfs = [&] (auto &self, int u, int p) -> void {
int v1 = 0, v2 = 0;
for (auto &v: path[u]) {
if (v != p) {
self(self, v, u);
if (dp[v] > v1) swap(v1, v2), v1 = dp[v];
else if (dp[v] > v2) v2 = dp[v];
}
}
if (nums[u] % to_check == 0) {
max_len = max(max_len, v1 + v2 + 1);
dp[u] = v1 + 1;
}
};
for (int i = 0; i <= M; i ++) {
if (cnt[i] * 2 > n) {
to_check = i, max_len = 0;
dfs(dfs, 0, -1);
if (max_len * 2 > n) return cout << "YES", 0;
}
}
cout << "NO";
return 0;
}
H. Beacon Towers
所有分割点只可能出现在两个前缀最大值之间。
且其间最多只能插入一个分割点,所以假设中间有 k个分割点,可以任选一个分割,或者不选,因此有 k+1种方案
+1为不选(不选也为答案)
浙公网安备 33010602011771号