A Tokitsukaze and All Zero Sequence
直接贪心即可
bool v[1010];
signed main() {
cf {
memset(v, 0, sizeof v);
n = read();
cnt = 0;
bool flag = 0;
rep(i, 1, n) {
a = read();
if (v[a]) flag = 1;
if (a == 0) cnt++;
v[a] = 1;
}
if (cnt)
cout << n - cnt << "\n";
else if (flag) {
cout << n << "\n";
} else
cout << n + 1 << "\n";
}
return 0;
}
B1 Tokitsukaze and Good 01-String (easy version)
贪心 观察 发现 奇数位置和偶数位置不同的话就需要操作一次
B2 Tokitsukaze and Good 01-String (hard version)
在B1的条件下,最小化不同的一堆0/一堆1的个数
那么对字符串某处 只有0/1两种选择
又要让连续的尽可能长,自然想到DP
状态转移的部分代码比较繁琐,但是好懂,将就着看
char s[N];
int f[N][2];
//前i个 ,结尾0/1串的 min操作数
//如果 i-2 i-3 一样都是0/1 他们不会被改变
signed main() {
cf {
n = read();
ans = 0;
scanf("%s", s + 1);
for (int i = 2; i <= n; i += 2) {
if (s[i] != s[i - 1]) ans++;
}
cout << ans << " ";
for (int i = 2; i <= n; i += 2) {
f[i][0] = f[i][1] = INF;
}
f[0][0] = f[0][1] = 1;
for (int i = 2; i <= n; i += 2) {
if (s[i] == s[i - 1]) {
if (s[i] == '1') {
if (f[i - 2][1] == INF)
f[i][1] = f[i - 2][0] + 1;
else if (f[i - 2][0] == INF)
f[i][1] = f[i - 2][1];
else {
f[i][1] = min(f[i - 2][1], f[i - 2][0] + 1);
}
} else {
if (f[i - 2][1] == INF)
f[i][0] = f[i - 2][0];
else if (f[i - 2][0] == INF)
f[i][0] = f[i - 2][1] + 1;
else {
f[i][0] = min(f[i - 2][1] + 1, f[i - 2][0]);
}
}
} else {
if (f[i - 2][1] == INF) {
f[i][1] = f[i - 2][0] + 1;
f[i][0] = f[i - 2][0];
} else if (f[i - 2][0] == INF) {
f[i][1] = f[i - 2][1];
f[i][0] = f[i - 2][1] + 1;
} else {
f[i][1] = min(f[i - 2][1], f[i - 2][0] + 1);
f[i][0] = min(f[i - 2][0], f[i - 2][1] + 1);
}
}
}
cout << min(f[n][0], f[n][1]) << "\n";
}
return 0;
}
C Tokitsukaze and Strange Inequality
一眼看上去就像某次leetcode周赛的好三元组
但是变成了四元
思路就是枚举c和d 暴力 加 前缀和 可过
这里顺手写了个树状数组
int u[N];
int c1[N], c2[N];
int ask(int a) {
int rs = 0;
for (; a; a -= lowbit(a)) {
rs += c1[a];
}
return rs;
}
void add(int a, int b) {
for (; a <= n; a += lowbit(a)) {
c1[a] += b;
}
return;
}
int askc(int a) {
int rs = 0;
for (; a; a -= lowbit(a)) {
rs += c2[a];
}
return rs;
}
void addc(int a, int b) {
for (; a <= n; a += lowbit(a)) {
c2[a] += b;
}
return;
}
signed main() {
cf {
n = read();
rep(i, 1, n) u[i] = read();
add(u[1], 1);
addc(u[n], 1);
ans = 0;
rep(b, 2, n - 1) {
rep(i, b + 1, n - 1) { addc(u[i], 1); }
rep(c, b + 1, n - 1) {
// n^2枚举b c
addc(u[c], -1);
// cout << ask(u[c] - 1) << " " << (askc(n) - askc(u[b])) << "\n";
ans += ask(u[c] - 1) * askc(u[b] - 1);
}
add(u[b], 1);
}
cout << ans << "\n";
rep(i, 1, n) c1[i] = 0, c2[i] = 0;
}
return 0;
}
D Tokitsukaze and Meeting
贪心/DP
见注释 身为div2D相对简单了些吧 列相当好想 行有点dp的感觉
char s[N];
int as[N];
int as2[N];
signed main() {
cf {
//如果是不同行 同列的 那么 后面无论怎么添加数 都是 同列的 所以有 1 就是1了
//所以在第一行满的时候 插新数 是 1 ans不变 如果 队尾是1 ans也不变 队尾0且新进的是1 ans++
n = read();
m = read();
t = n * m;
ans = 0;
scanf("%s", s + 1);
queue q;
rep(i, 1, m) {
q.push(s[i] - '0');
if (s[i] == '1') ans++;
as[i] = ans;
if (as[i]) as2[i]++;
}
rep(i, m + 1, t) {
int now = q.front();
q.pop();
if (now == 0 && s[i] == '0') {
q.push(0);
as[i] = as[i - 1];
}
if (now == 1 && s[i] == '0') {
q.push(1);
as[i] = as[i - 1];
}
if (now == 0 && s[i] == '1') {
q.push(1);
as[i] = as[i - 1] + 1;
}
if (now == 1 && s[i] == '1') {
q.push(1);
as[i] = as[i - 1];
}
}
//以上列
//下面考虑行
// 经过m个数的插入之后 相当于当前的整个区域往下移了一格
// 那么只要新进来的m个数有一个1 就可以ans+1 简单的dp一下就可以了
int sum = 0;
rep(i, 1, m) if (s[i] == '1') sum++;
rep(i, m + 1, t) {
as2[i] = as2[i - m];
sum -= s[i - m] - '0';
sum += s[i] - '0';
if (sum) as2[i]++;
} // i~i-m有1 就加1
rep(i, 1, t) cout << as[i] + as2[i] << " ";
cout << "\n";
rep(i, 1, t) as[i] = 0, as2[i] = 0;
}
return 0;
}
[点击并拖拽以移动]
E Tokitsukaze and Two Colorful Tapes
就最近哪场div2吧好像也有个循环节问题
求和绝对值最大 那么一定是到n的 毕竟不会减小答案
然后这里并查集找环了 暴力找环也是可以的
然后确定了环 贪心的让相邻的差的最多就可以了
int ca[N], cb[N];
int f[N];
int find(int x) {
if (x == f[x]) return x;
return f[x] = find(f[x]);
}
map p;
vector v;
signed main() {
cf {
n = read();
p.clear();
ans = 0;
rep(i, 1, n) ca[i] = read();
rep(i, 1, n) f[i] = i;
rep(i, 1, n) {
cb[i] = read();
a = find(ca[i]);
b = find(cb[i]);
if (a != b) f[a] = b;
}
rep(i, 1, n) { p[find(ca[i])]++; }
int l = 1, r = n; //染色的最小/大值
for (auto [_, cntt] : p) {
int kk = cntt;
if (kk == 1) continue;
v.clear();
if (kk & 1) kk--;
rep(i, 1, kk) {
if (i & 1)
v.push_back(r--);
else
v.push_back(l++);
}
for (int i = 1; i < kk; i++)
ans += abs(v[i] - v[i - 1]);
ans += abs(v[kk - 1] - v[0]);
}
cout << ans << "\n";
}
return 0;
}
要注意:奇环最后一个是暂时不赋值的 因为他对答案没有影响
而若先赋值了 会让之后的最小/大值 不是是真正的最小/大值
这题主要问题就在这里了 提前赋值会让贪心策略失败