对于第一个条件,两个数字 x 和 y 按位与大于 0,显然 x 和 y 的对应二进制位中至少需要有 1 位同时是 1,那么为了让 y 尽可能小,我们取 x 最后一位 1 即前面位的所有 0 即可。例如 10=(1010)2,此时取 2=(10)2 即可,也就是 lowbit(10)。 浅谈lowbit运算 - Seaway-Fu - 博客园
对于第二个条件,两个数字 x 和 y 按位异或大于 0,那么我们至少需要有一位二进制位不同。在第一个条件下我们取了 y′=lowbit(x) 。如果此时 y′=x,那么就取此时的 y=y′ 即可。
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) constint N = 1e4 + 10; int a[N], n, t;
boolcheck(int k){ priority_queue<int, vector<int>, greater<int> > q; for(int i = 1; i <= k; i ++ ) q.push(a[i]); for(int i = k + 1; i <= n; i ++ ){ int now = q.top(); q.pop(); if(now + a[i] > t) returnfalse; // 超出时间限制 q.push(now + a[i]); } returntrue; }
intmain(){ ios;
cin >> n >> t; for(int i = 1; i <= n; i ++ ) cin >> a[i]; int l = 1, r = n; while(l < r){ int mid = l + r >> 1; if(check(mid)) r = mid; else l = mid + 1; } cout << r << '\n';
return0; }
E. 早苗的机动战士高达梦
题目描述
给定一个图,图中构成多个连通块。先输出当前图中的连通块个数,然后给定 k 次询问,每次去除一个点及其邻接的边,问去除当前这个点时图中有多少连通块。「YAC Round 4」早苗的机动战士高达梦
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) #define fi first #define se second constint N = 4e5 + 10;
int n, m, k, fa[N], a[N], res[N]; int h[N], e[N], ne[N], idx; bool ban[N];
voidadd(int a, int b){ e[ ++ idx] = b, ne[idx] = h[a], h[a] = idx; }
intfind(int x){ return fa[x] == x ? x : fa[x] = find(fa[x]); }
intmain(){ ios;
cin >> n >> m; while(m -- ){ int u, v; cin >> u >> v; add(u, v), add(v, u); } cin >> k; for(int i = 1; i <= k; i ++ ) cin >> a[i], ban[a[i]] = true; for(int i = 0; i < n; i ++ ) fa[i] = i;
// 先得到最后一次询问之后的连通块个数 int tot = n - k; // 最后一次询问之后图中共有 n - k 个点 for(int u = 0; u < n; u ++ ){ if(ban[u]) continue; for(int i = h[u]; i; i = ne[i]){ int v = e[i]; if(ban[v]) continue; int fx = find(u), fy = find(v); if(fx != fy) fa[fy] = fx, tot -- ; // 合并两个连通块 } } res[k + 1] = tot;
// 逆向还原 for(int j = k; j; j -- ){ int u = a[j]; ban[u] = false; // 加入点 tot ++ ; // 一个点一个连通块 for(int i = h[u]; i; i = ne[i]){ int v = e[i]; if(ban[v]) continue; int fx = find(u), fy = find(v); if(fx != fy) fa[fy] = fx, tot -- ; // 合并两个连通块 } res[j] = tot; }
// 输出答案 for(int i = 1; i <= k + 1; i ++ ) cout << res[i] << '\n';
return0; }
F. 爱丽丝送给魔理沙的手链
题目描述
假设 b 为蓝色,g 为金色。给定一个长度 n,求出用 b 和 g 可以构造出的相邻元素不能同时为金色,即不能同时为 g(或者说相邻元素至少有一个为蓝色,即至少有一个为 b) 的长度为 n 的 环状 字符串方案数。「YAC Round 4」爱丽丝送给魔理沙的手链
解题思路 dp + 矩阵加速
我们可以先考虑一下 n≤106 时如何解决这个问题。显然,我们可以用动态规划解决这个子问题。
用 dp[i][0] 表示构造的长度为 i 且第 i 个宝石选用 金色宝石 的方案数; dp[i][1] 表示构造的长度为 i 且第 i 个宝石选用 蓝色宝石 的方案数。
题中要求相邻的两个不能同时为金色。对于 dp[i][0] ,第 i 个选择了金色,那么前一位只能用蓝色;对于 dp[i][1],第 i 个选择了蓝色,那么前一位选择蓝色或金色都可以。 故状态转移方程如下: