Codeforces Round 789 div2 A-E题解 & 处理手法思考

A. Tokitsukaze and All Zero Sequence

这题给一个数列,每次操作

  • 对于两个不相同的数字可以吧大的变成min,
  • 两个相同的话一个变为0

问最少操作多少次能将整个数组变为0

首先这个操作1开始容易想到,如果数组中原来有0,那么就可以操作n - |0的个数|次使得数组全部变为0

然后我们再看操作2,显然我们可以先把一个数字变成0,然后再用操作2去同化其他非0的,那么如果存在两个相同的数字,我们可以省略步骤1,使用步骤2进行操作
如果不存在的话,那么还需要一步把另一个数字变成相同的数字才能变0,这个很好想

#include <bits/stdc++.h>
using namespace std;
constexpr int limit =  (2000000 + 5);//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define ff(a) printf("%d\n",a );
#define pi(a, b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a  ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].nxt)
#define FOPEN freopen("C:\\Users\\tiany\\CLionProjects\\akioi\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\Users\\tiany\\CLionProjects\\akioi\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;

inline ll read() {
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    ll sign = 1, x = 0;
    char s = getchar();
    while (s > '9' || s < '0') {
        if (s == '-')sign = -1;
        s = getchar();
    }
    while (s >= '0' && s <= '9') {
        x = (x << 3) + (x << 1) + s - '0';
        s = getchar();
    }
    return x * sign;
#undef getchar
}//快读
void print(ll x) {
    if (x / 10) print(x / 10);
    *O++ = x % 10 + '0';
}

void write(ll x, char c = 't') {
    if (x < 0)putchar('-'), x = -x;
    print(x);
    if (!isalpha(c))*O++ = c;
    fwrite(obuf, O - obuf, 1, stdout);
    O = obuf;
}
constexpr ll mod = 1e9 + 7;
ll quick_pow(ll base, ll expo){
    ll ans = 1;
    while(expo){
        if(expo & 1) ans = ans * base % mod;
        base = base * base % mod;
        expo >>= 1;
    }
    return ans;
}
int n,m;
int a[limit];
void solve(){
    cin>>n;
    map<int, int>mp;
    rep(i, 1, n){
        cin>>a[i];
        mp[a[i]]++;
    }
    //如果是0的话就直接用0输出
    if(mp[0]){
        cout<<n - mp[0]<<endl;
        return;
    }else{
        int ans = 2;
        for(auto [k, v] : mp){
            if(v > 1){
                ans--;
                break;
            }
        }
        cout<<ans + n - 1<<endl;
    }
};
int32_t main() {
#ifdef LOCAL
    FOPEN;
//    FOUT;
#endif
    FASTIO
    int kase;
    cin>>kase;
    while (kase--)
        solve();
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
    return 0;
}

B1. Tokitsukaze and Good 01-String (easy version)

B题问分若干段,每段长度为偶数,那么问最少需要改动多少个位置才能完成这种划分

这题问的方式很有误导性,我直接写了个模拟,但捂在手里不敢交,后来想了想好像没问题,交了一发AC

#include <bits/stdc++.h>
using namespace std;
constexpr int limit =  (2000000 + 5);//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define ff(a) printf("%d\n",a );
#define pi(a, b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a  ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].nxt)
#define FOPEN freopen("C:\\Users\\tiany\\CLionProjects\\akioi\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\Users\\tiany\\CLionProjects\\akioi\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;

inline ll read() {
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    ll sign = 1, x = 0;
    char s = getchar();
    while (s > '9' || s < '0') {
        if (s == '-')sign = -1;
        s = getchar();
    }
    while (s >= '0' && s <= '9') {
        x = (x << 3) + (x << 1) + s - '0';
        s = getchar();
    }
    return x * sign;
#undef getchar
}//快读
void print(ll x) {
    if (x / 10) print(x / 10);
    *O++ = x % 10 + '0';
}

void write(ll x, char c = 't') {
    if (x < 0)putchar('-'), x = -x;
    print(x);
    if (!isalpha(c))*O++ = c;
    fwrite(obuf, O - obuf, 1, stdout);
    O = obuf;
}
constexpr ll mod = 1e9 + 7;
ll quick_pow(ll base, ll expo){
    ll ans = 1;
    while(expo){
        if(expo & 1) ans = ans * base % mod;
        base = base * base % mod;
        expo >>= 1;
    }
    return ans;
}
int n,m;
int a[limit];
void solve(){
    cin>>n;
    string str;
    cin>>str;
    str = " " + str;
    vector<pi(int, int)>v;
    rep(i,1,n){
        if(v.empty() || v.back().first != str[i] - '0'){
            v.push_back({str[i] - '0', 1});
        }else{
            v.back().second++;
        }
    }
    int ans = 0;
    for(int i = 0; i < (int)v.size() - 1; i++){
        if(v[i].second & 1){
            ans++;
            v[i + 1].second--;
        }
    }
    cout<<ans<<endl;
};
int32_t main() {
#ifdef LOCAL
    FOPEN;
//    FOUT;
#endif
    FASTIO
    int kase;
    cin>>kase;
    while (kase--)
        solve();
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
    return 0;
}

B2. Tokitsukaze and Good 01-String (hard version)

这个题和上个题题意相同,但多问了个,如果分段要求段数最少,该怎么改

首先这种问题不要懒,很多easy和hard version其实是两种不同的问题解决方法,不要蹲在easy上去想hard。上次div3教训应该是很深刻了。

这个我们需要回归本质,去想偶数,那么所有偶数都能被2整除,2就是偶数最小单位,我们去看这个最小单位,然后如果我们有n/2个这种单位,那么每个单位全0或者全1的费用可以很容易地被算出来,然后上一段的颜色是什么就不会影响这一段的了,我们可以定义状态了,dp[i][j], i代表位数,j代表以i结尾的2段全0还是全1

然后我们只需要从上一个继承过来最小费用就行了

#include <bits/stdc++.h>
using namespace std;
constexpr int limit =  (2000000 + 5);//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define ff(a) printf("%d\n",a );
#define pi(a, b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a  ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].nxt)
#define FOPEN freopen("C:\\Users\\tiany\\CLionProjects\\akioi\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\Users\\tiany\\CLionProjects\\akioi\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;

inline ll read() {
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    ll sign = 1, x = 0;
    char s = getchar();
    while (s > '9' || s < '0') {
        if (s == '-')sign = -1;
        s = getchar();
    }
    while (s >= '0' && s <= '9') {
        x = (x << 3) + (x << 1) + s - '0';
        s = getchar();
    }
    return x * sign;
#undef getchar
}//快读
void print(ll x) {
    if (x / 10) print(x / 10);
    *O++ = x % 10 + '0';
}

void write(ll x, char c = 't') {
    if (x < 0)putchar('-'), x = -x;
    print(x);
    if (!isalpha(c))*O++ = c;
    fwrite(obuf, O - obuf, 1, stdout);
    O = obuf;
}
constexpr ll mod = 1e9 + 7;
ll quick_pow(ll base, ll expo){
    ll ans = 1;
    while(expo){
        if(expo & 1) ans = ans * base % mod;
        base = base * base % mod;
        expo >>= 1;
    }
    return ans;
}
int n,m;
int a[limit];
int dp[limit][2];
void solve(){
    cin>>n;
    string str;
    cin>>str;
    str = " " + str;
    vector<pi(int, int)>v;
    rep(i,1,n){
        if(v.empty() or v.back().first != str[i] - '0'){
            v.push_back({str[i] - '0', 1});
        }else{
            v.back().second++;
        }
    }
    int ans = 0;
    for(int i = 0; i < (int)v.size() - 1; i++){
        if(v[i].second & 1){
            ans++;
            v[i + 1].second--;
            v[i].second++;
        }
    }
    if(!ans){
        cout<<ans<<" "<<v.size()<<endl;
        return;
    }
    rep(i,1,n){
        fill(dp[i], dp[i] + 2, INF);
    }
    if(str[1] != str[2]){
        dp[1][0] = 1;
        dp[1][1] = 1;
    }else{
        dp[1][str[1] - '0'] = 1;
    }
    for(int i = 3; i <= n; i += 2){
        if(str[i] != str[i + 1]){
            dp[i][0] = min(dp[i - 2][0], dp[i - 2][1] + 1);
            dp[i][1] = min(dp[i - 2][1], dp[i - 2][0] + 1);
        }else{
            int x = str[i] - '0';
            dp[i][x] = min(dp[i - 2][x], dp[i - 2][x ^ 1] + 1);
        }
    }
    cout<<ans<<" "<<*min_element(dp[n - 1], dp[n - 1] + 2)<<endl;
};
int32_t main() {
#ifdef LOCAL
    FOPEN;
//    FOUT;
#endif
    FASTIO
    int kase;
    cin>>kase;
    while (kase--)
        solve();
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
    return 0;
}

其实也没有很难

C. Tokitsukaze and Strange Inequality

这题是挑选下标四元组(a,b,c,d),要求abcd为升序,不能重合,并且要满足第一个下标元素小于第三个下标,第二个下标元素小于第四个
输入distinct

那么这个问题很容易想到用树状数组去维护,输入5000,应该是平方算法,所以我们可以枚举两个支点,观察发现最好维护的地方就是枚举b和c,那么我们只要找出来

  • b前面小于d的
  • c后面小于a的

这两个都很容易能够求到
乘起来就行了

#include <bits/stdc++.h>
using namespace std;
constexpr int limit =  (2000000 + 5);//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define ff(a) printf("%d\n",a );
#define pi(a, b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a  ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].nxt)
#define FOPEN freopen("C:\\Users\\tiany\\CLionProjects\\akioi\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\Users\\tiany\\CLionProjects\\akioi\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;

inline ll read() {
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    ll sign = 1, x = 0;
    char s = getchar();
    while (s > '9' || s < '0') {
        if (s == '-')sign = -1;
        s = getchar();
    }
    while (s >= '0' && s <= '9') {
        x = (x << 3) + (x << 1) + s - '0';
        s = getchar();
    }
    return x * sign;
#undef getchar
}//快读
void print(ll x) {
    if (x / 10) print(x / 10);
    *O++ = x % 10 + '0';
}

void write(ll x, char c = 't') {
    if (x < 0)putchar('-'), x = -x;
    print(x);
    if (!isalpha(c))*O++ = c;
    fwrite(obuf, O - obuf, 1, stdout);
    O = obuf;
}
constexpr ll mod = 1e9 + 7;
ll quick_pow(ll base, ll expo){
    ll ans = 1;
    while(expo){
        if(expo & 1) ans = ans * base % mod;
        base = base * base % mod;
        expo >>= 1;
    }
    return ans;
}
int n,m;
int a[limit];
int tree[limit];
#define int ll
int tree2[limit];
void add(int pos, int val){
    while(pos <= n){
        tree[pos] += val;
        pos += lowbit(pos);
    }
}
int query(int pos){
    int ans = 0;
    while(pos){
        ans += tree[pos];
        pos -= lowbit(pos);
    }
    return ans;
}
void add2(int pos, int val){
    while(pos <= n){
        tree2[pos] += val;
        pos += lowbit(pos);
    }
}
int query2(int pos){
    int ans = 0;
    while(pos){
        ans += tree2[pos];
        pos -= lowbit(pos);
    }
    return ans;
}

void solve(){
    cin>>n;
    rep(i,1,n){
        cin>>a[i];
    }
    ll ans = 0;
    rep(i,1,n){
        rep(j,1,n){
            tree[j] = 0;
            tree2[j] = 0;
        }
        rep(j,1, i - 1){
            add(a[j], 1);
        }
        //把后面的清空
        per(j,i + 1,n){
            add2(a[j], 1);
        }
        rep(j, i + 1, n){
            add2(a[j], -1);
            ll fst = query(a[j]);
            ll scd = query2(a[i] - 1);
            ans += fst * scd;
        }
    }
    cout<<ans<<endl;
};
int32_t main() {
#ifdef LOCAL
    FOPEN;
//    FOUT;
#endif
    FASTIO
    int kase;
    cin>>kase;
    while (kase--)
        solve();
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
    return 0;
}

D. Tokitsukaze and Meeting

太麻烦没看,不会,直接跳E

E. Tokitsukaze and Two Colorful Tapes

这个题是给出两个数组permutation,如果是相同元素位置要填一样的数字,问 \sum{abs(a[i] - b[i])}的最大值

读题花了半个小时

这个问题经过上次gdb 2022的时候的懵逼,看到这种问题首先想到找环,然后想到了带权并查集,我说上次怎么这么多人直接想到环了,搜得死奶,学到了。

感觉这类问题的处理手法往往非常类似,比如两个数组中a和b必须存在某种constraint,那么这种约束肯定有某种传递性,因为是两个数组,所以要么是孤点,要么是简单环,然后根据环我们再想其他的。其实他喵的这种问题就很妙,但是你题量不够还是不行。

然后找环之后,根据环大小排个序,我们贪心的交错安排权值,记得最后要减一下。

然而wa2,然后看题解发现,好像点个数为奇数的环并不能对答案产生什么有效贡献,所以奇数的那个点我们不主动安排权值,避免影响后面的

#include <bits/stdc++.h>
using namespace std;
constexpr int limit =  (2000000 + 5);//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-9
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define ff(a) printf("%d\n",a );
#define pi(a, b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a  ; --i)
#define MOD 998244353
#define traverse(u) for(int i = head[u]; ~i ; i = edge[i].nxt)
#define FOPEN freopen("C:\\Users\\tiany\\CLionProjects\\akioi\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\Users\\tiany\\CLionProjects\\akioi\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;

inline ll read() {
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    ll sign = 1, x = 0;
    char s = getchar();
    while (s > '9' || s < '0') {
        if (s == '-')sign = -1;
        s = getchar();
    }
    while (s >= '0' && s <= '9') {
        x = (x << 3) + (x << 1) + s - '0';
        s = getchar();
    }
    return x * sign;
#undef getchar
}//快读
void print(ll x) {
    if (x / 10) print(x / 10);
    *O++ = x % 10 + '0';
}

void write(ll x, char c = 't') {
    if (x < 0)putchar('-'), x = -x;
    print(x);
    if (!isalpha(c))*O++ = c;
    fwrite(obuf, O - obuf, 1, stdout);
    O = obuf;
}
constexpr ll mod = 1e9 + 7;
ll quick_pow(ll base, ll expo){
    ll ans = 1;
    while(expo){
        if(expo & 1) ans = ans * base % mod;
        base = base * base % mod;
        expo >>= 1;
    }
    return ans;
}
#define int ll
int n,m;
int a[limit];
vector<int>g[limit];
int fa[limit];
int sizes[limit];
int find(int x){
    return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void merge(int x,int y){
    int fx = find(x);
    int fy = find(y);
    if(fx == fy) return;
    fa[fx] = fy;
    sizes[fy] += sizes[fx];
}
struct node{
    ll val, id;
    bool operator < (const node &rhs) const{
        return val < rhs.val;
    }
};
void solve(){
    multiset<int> pa, pb;
    cin >> n;
    rep(i,1,n){
        cin >> a[i];
        fa[i] = i;
        g[i].clear();
    }
    rep(i,1,n) {
        cin >> a[i + 1 + n];
        pa.insert(i);
        pb.insert(i);
        if (a[i] == a[i + 1 + n]) continue;
        merge(a[i], a[i + 1 + n]);
    }
    map<int, int>mp;
    rep(i,1,n){
        mp[find(i)]++;
    }
    vector<ll> circle;
    rep(i,1,n){
        if(find(i) == i and mp[i] > 1){
            circle.push_back(mp[i]);
        }
    }
    ll ans = 0;
    sort(circle.begin(), circle.end());
    for(auto v : circle | ranges::views::reverse){
//        cout<<v<<endl;
        vector<int>t;
        if(v & 1)--v;
        rep(i,1,v){
            if(i & 1){
                t.push_back(*pa.begin());
                pa.extract(t.back());
            }else{
                t.push_back(*pa.rbegin());
                pa.extract(t.back());
            }
//            cout<<t[i]<<" ";
        }
//        cout<<endl;
        rep(i,1, v - 1){
            ans += abs(t[i] - t[i - 1]);
        }
        ans += abs(t.front() - t.back());

    }
//    cout<<endl;
    cout<<ans<<endl;


};
int32_t main() {
#ifdef LOCAL
    FOPEN;
//    FOUT;
#endif
    FASTIO
    int kase;
    cin>>kase;
    while (kase--)
        solve();
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
    return 0;
}

感觉做点题挺好的,头脑清澈,很多问题并非无解,只不过自己题量不够,想不到这一层而已。

posted @ 2023-01-02 05:34  tiany7  阅读(13)  评论(0编辑  收藏  举报