Educational Codeforces Round 161(div. 2)
思维
若在第 i i i个字符处, c i c_i ci与 a i , b i a_i,b_i ai,bi中至少一个相等,则无法在 t i t_i ti 处构造字符使得 c c c不匹配。反证,若在此处 c i c_i ci无法匹配,则在此处与之相同的 a i a_i ai或 b i b_i bi也无法匹配,即 a a a或 b b b无法匹配,不满足题意。
若在第 i i i个字符处, c i c_i ci与 a i , b i a_i,b_i ai,bi均不相同相等,则在 t i t_i ti处构造 c i c_i ci的大写形式即可,使得 c i c_i ci不满足但 a i , b i a_i,b_i ai,bi均满足。
综上,即是否存在下标 i i i,使 c i ≠ a i c_i\ne a_i ci=ai且 c i ≠ b i c_i\neq b_i ci=bi。
#include
using namespace std;
int main() {
cin.tie(0)->sync_with_stdio(false);
int t;
cin >> t;
while (t--) {
int n;
string a, b, c;
cin >> n >> a >> b >> c;
int i = -1;
while (++i < n)
if (b[i] != c[i] && a[i] != c[i]) break;
cout << (i == n ? "No\n" : "Yes\n");
}
}
数学
每根棍子长度为 2 2 2的整次幂,则最长两根棍子的长度必须相同。若不同,则最长的比剩下的长至少两倍以上,剩下两根之和不大于最长那根,不满足题意。故最长两根长度相同,在此基础上,第三根长度则无限制(当然不能长度最长长度)。
每根棍子的长度为 2 2 2的整次幂 2 k 2^k 2k,不妨设棍子长度为 2 a , 2 b , 2 c ( 2 a ≥ 2 b ≥ 2 c ) 2^a,2^b,2^c(2^a\geq2^b\geq2^c) 2a,2b,2c(2a≥2b≥2c),若 2 a > 2 b 2^a>2^b 2a>2b即 2 a − 1 ≥ 2 b 2^{a-1}\geq2^b 2a−1≥2b,则 2 a = 2 × 2 a − 1 ≥ 2 b + 2 c 2^a=2\times2^{a-1}\geq2^b+2^c 2a=2×2a−1≥2b+2c,无法构成三角形,故 2 a = 2 b ≥ 2 c 2^a=2^b\geq2^c 2a=2b≥2c。
若长度为 2 k 2^k 2k的有 x x x根,长度 ≤ 2 k \leq2^k ≤2k的有 y y y根, x ≥ 2 x\geq2 x≥2时,仅由两根 2 k 2^k 2k长度的棍子(剩下那根长度 < 2 k <2^k <2k)构成的三角形的个数为 ( x − y ) C x 2 (x-y)C_x^2 (x−y)Cx2, x ≥ 3 x\geq3 x≥3时,由三根 2 k 2^k 2k长度的棍子构成的三角形个数为 C x 3 C_x^3 Cx3。对所有满足条件的 k k k依上述两式求和即可。
map
计数时#include
using namespace std;
typedef long long LL;
int main() {
cin.tie(0)->sync_with_stdio(false);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
map<int, int> cnt;
for (int i = 0, x; i < n; i++) cin >> x, cnt[x]++;
LL res = 0, sum = 0;;
for (const auto& x : cnt) {
LL v = x.second;
res += (sum * v * (v - 1) / 2) + (v * (v - 1) * (v - 2) / 6);
sum += v;
}
cout << res << '\n';
}
}
前缀和
只能向前或向后前行,按向前与向后时的移动花费分别打遍前缀和。
#include
using namespace std;
typedef long long LL;
const int N = 1e5 + 1;
LL arr[N] = { INT_MIN }, pre[N], post[N];
int main() {
cin.tie(0)->sync_with_stdio(false);
int t;
cin >> t;
while (t--) {
int n, m;
cin >> n;
post[n + 1] = 0;
arr[n + 1] = INT_MAX;
for (int i = 1; i <= n; i++) cin >> arr[i];
for (int i = 1; i < n; i++)
pre[i + 1] = pre[i] + (arr[i] - arr[i - 1] > arr[i + 1] - arr[i] ? 1 : arr[i + 1] - arr[i]);
for (int i = n; i > 1; i--)
post[i - 1] = post[i] + (arr[i] - arr[i - 1] > arr[i + 1] - arr[i] ? arr[i] - arr[i - 1] : 1);
cin >> m;
while (m--) {
int l, r;
cin >> l >> r;
if (l < r) cout << pre[r] - pre[l] << '\n';
else cout << post[r] - post[l] << '\n';
}
}
}
搜索
每个怪物若死亡,则只会影响周围两边的怪物,而非影响全图;故每轮,我们只需要考虑上一轮死亡怪物左右两侧的情况,每个怪物死亡,则将左右两侧的怪物加入更新队列。
因为每一轮怪物的攻击是同时进行的,也即如果这个怪物在本轮死亡,也会将伤害传递给左右两侧的怪物。此处步骤要分层,先检查更新队列,将死亡怪物推入移除队列,待更新队列全部检查完毕后,再移除移除队列中的怪物,同时将死亡(被移除)怪物两侧的怪物推入更新队列,如此往复。
使用两个数组模拟双链表,表示该怪物左侧下标与右侧下标。
#include
using namespace std;
const int N = 3e5 + 2;
int a[N], d[N], vis[N] = { 2 };
int l[N], r[N];
int q1[N], q2[N];
int main() {
cin.tie(0)->sync_with_stdio(false);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
a[n + 1] = d[n + 1] = 0;
vis[n + 1] = 2;
for (int i = 1; i <= n; i++) cin >> d[i];
for (int i = 1; i <= n; i++) cin >> a[i], vis[i] = 0, l[i] = i - 1, r[i] = i + 1;
int idx1 = 0, idx2 = 0;
for (int i = 1; i <= n; i++)
if (d[i - 1] + d[i + 1] > a[i]) q1[idx1++] = i;//将要死亡的推入更新队列(其实把所有元素都推入亦可)
for (int k = 1; k <= n; k++) {
int res = 0;
for (int i = 0; i < idx1; i++) {//检查更新队列
int v = q1[i];
if (vis[v] == 2) continue;//已死亡,避免重复检查带来的额外开销
if (d[l[v]] + d[r[v]] > a[v]) q2[idx2++] = v, res++, vis[v] = 2;//推入移除队列,标记为2,答案+1,进入移除队列
else vis[v] = 0;//清空标记,以待本次更新
}
idx1 = 0;
for (int i = 0; i < idx2; i++) {//检查移除队列
int v = q2[i];
if (!vis[r[l[v]] = r[v]]) vis[q1[idx1++] = r[v]] = 1;//若右节点为进入更新队列,则加入,并标记为1,表示已进入更新队列
if (!vis[l[r[v]] = l[v]]) vis[q1[idx1++] = l[v]] = 1;//避免重复检查带来的额外开销(最多可能进入两次)
}
idx2 = 0;
cout << res << (k == n ? '\n' : ' ');
}
}
}
位运算,构造
假设这样一条主干序列,其严格递增,如 1 , 2 , ⋯ , n 1,2,\cdots,n 1,2,⋯,n,其每个数可以任意选择(甚至全不选),其剩下的均构成严格递增序列,其严格递增子序列个数为 2 n 2^n 2n。
在某处插入全序列最小值,如 1 , 2 , 3 , 4 , 5 1,2,3,4,5 1,2,3,4,5,插入 0 0 0后变为 1 , 2 , 3 , 0 , 4 , 5 1,2,3,0,4,5 1,2,3,0,4,5。该 0 0 0不选,则剩下数构成一条长度为 5 5 5的主干序列,贡献 2 5 2^5 25个严格递增子序列;选择该 0 0 0,则该 0 0 0左侧的所有数均不能选择( 0 0 0为全序列最小数)右侧的 4 , 5 4,5 4,5构成主干序列,可以任意选择,贡献 2 5 2^5 25。
如此,我们往一条主干序列中不断插入同一个最小值(若不同则会相互影响构成新的子序列),得到 2 n + 2 a 1 + 2 a 2 + ⋯ = X 2^n+2^{a_1}+2^{a_2}+\cdots=X 2n+2a1+2a2+⋯=X。
如 X = 13 = 110 1 B X=13=1101_B X=13=1101B,主干序列 1 , 2 , 3 1,2,3 1,2,3贡献 2 8 2^8 28,在 1 , 2 1,2 1,2中间插入 0 0 0新增贡献 2 2 = 2 2^2=2 22=2,在 3 3 3后面插入 0 0 0新贡献 2 = 1 2^=1 2=1,得到序列 1 , 0 , 2 , 3 , 0 1,0,2,3,0 1,0,2,3,0,满足题意。
#include
using namespace std;
typedef long long LL;
int main() {
cin.tie(0)->sync_with_stdio(false);
int t;
cin >> t;
while (t--) {
LL n, k = 200;
cin >> n;
vector<int> res;
while (n > 1) {
if (n & 1) res.push_back(0);
res.push_back(k--);
n >>= 1;
}
cout << res.size() << '\n';
for (int i = res.size() - 1; i >= 0; i--) cout << res[i] << (i ? ' ' : '\n');
}
}
有实力再看,私密马萨