Codeforces Round #751 (Div. 2)

Codeforces Round #751 (Div. 2)

知识点整理:

题号知识点难度备注
A字符串800
B构造1100
C数学1300
DBFS,DP1900
E分治,贪心,线段树2300
F排序,贪心2700

A题

题意:

给你一个字符串s,把他拆成两个字符串,a和b,要求a的字典序最小。

题解:

找到s里最小的字符,单独把它拿出来,然后把剩下的构成一个新字符串。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int MAXN = 1e5 + 10;
const int MOD = 1e9 + 7;

int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    ios::sync_with_stdio(false), cin.tie(0);

    int t;
    string s;

    cin>>t;
    while(t--) {
        cin>>s;
        char m = CHAR_MAX;
        int id = 0;
        for(int i=0;i<s.size();i++) {
            char ch = s[i];
            if (ch < m) {
                m = ch;
                id = i;
            }
        }

        s.erase(id, 1);
        cout << m << ' ' << s << endl;
    }
    return 0;
}

B题

题意:

给你个数组 A A A, 做以下操作若干次:

把上一次每个数出现的次数替换成下一轮的数。

给你 q q q次询问,问 k k k轮的时候, a i a_i ai是多少?

题解:

写几次发现操作若干次之后就不会变了。

所以把变的都记下来,直到不变为止。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int MAXN = 2e3 + 10;
const int MOD = 1e9 + 7;

int t, n, q, x, k;
int a[MAXN], b[MAXN][MAXN];

map<int, int> cnt;

bool check() {
    for (auto [k, v] : cnt) {
        if (k != v)
            return true;
    }
    return false;
}
int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    ios::sync_with_stdio(false), cin.tie(0);
    cin >> t;
    while (t--) {
        cnt.clear();
        cin >> n;
        for (int i = 1; i <= n;i++) {
            cin >> a[i];
            cnt[a[i]]++;
            b[0][i] = a[i];
        }
        int j = 1;

        while (check()) {
            for (int i = 1; i <= n; i++) {
                b[j][i] = cnt[b[j - 1][i]];
            }
            cnt.clear();
            for (int i = 1; i <= n; i++) {
                cnt[b[j][i]]++;
            }
            j++;
        }
        j--;
        cin >> q;
        while (q--) {
            cin >> x >> k;
            cout << b[min(j, k)][x] << endl;
        }
    }

    return 0;
}

C题

题意:

给你个数组 A A A, 让你进行一个 k k k-消除操作:

  • A A A中找 k k k个数
  • 求他们的and值,记作x
  • 这k个数都减去x

重复上面操作直到全变成0,求所有可行的k

题解:

把数组里面每个数按二进制位拆开,发现每次都是找 k k k个数同时变0,否则不变

所以,要想让这个 k k k可行,必须是每一位中1的个数的gcd,这样才可以每次选k个数让他同时变0.

那么k的最大值既然知道了,其所有约数也都是答案。

特殊的,如果全都是0,是一种特殊情况,输出所有1~n

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int MAXN = 2e5 + 10;
const int MOD = 1e9 + 7;

int t,n,a[MAXN];

int cnt[30];
int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    ios::sync_with_stdio(false), cin.tie(0);
    cin>>t;
    while(t--){
        int n;
        cin >> n;
        for(int i=1; i<=n; i++)
            cin>>a[i];
        
        memset(cnt, 0, sizeof(cnt));
        int m = 0;
        for (int i = 0; i < 30; i++) {
            int mask = 1<<i;
            for (int j = 1; j <= n; j++) {
                if (a[j]&mask)
                    cnt[i]++;
            }

            m = __gcd(m, cnt[i]);
        }

        // 全是0
        if (m == 0) {
            for (int i = 1; i <= n; i++) cout << i << ' ';
            cout << endl;
        } else {
            // 输出m的约数
            set<int> s;
            for (int i = 1; i*i <= m; i++) 
                if (m%i==0) {
                    s.insert(i);
                    s.insert(m/i);
                }
            
            for (auto it : s)
                cout << it << ' ';
            cout << endl;
        }        
    }
    return 0;
}

D题

题意

题目大意就是,你现在在一个深度为m的坑里,给你两个数组a和b

a[i]表示深度为i时最多往上跳多少

b[i]表示你跳到这里之后必须要往下滑多少

问你跳出去至少几步,以及输出方案

题解

一开始tle了,发现可以优化:每次枚举一个状态 < j , k > <j, k> <j,k>, 其中 j j j是从上一步跳上来的点, k k k是滑下去的点。

当前处在 k k k位置,那么下一步的跳上去的点可能是 [ k − a [ k ] , k ] [k-a[k], k] [ka[k],k]之间,而如果这些值都搜索过之后,后面再算 k − a [ k ] k-a[k] ka[k]以后的 j j j值就都没必要了,根据bfs的特性,后面搜的步数大于等于前面的,所以再重复搜 j j j也不可能得到更优解,因此每次搜索状态之后,更新枚举过的 k − a [ k ] k-a[k] ka[k]的最小值,只有比他更小才有搜索的必要。因此 j j j是单调递减的,整个时间复杂度可以优化到 O ( n ) O(n) O(n).

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int MAXN = 3e5 + 10;
const int MOD = 1e9 + 7;

int n, a[MAXN], b[MAXN];
int dis[MAXN];

int pre[MAXN];

typedef struct Node {
    int x;
    int y;
    int steps;
} Node;

int bfs(pii st) {
    int x = st.first, y = st.second;

    memset(dis, 0x3f, sizeof(dis));

    queue<Node> q;
    q.push({ x, y, 0 });
    dis[n] = 0;
    int dep = n;
    
    while (!q.empty()) {
        auto nd = q.front();
        q.pop();

        int j = nd.x, k = nd.y;
        if (j == 0) {
            return dis[j];
        }

        for (int i = a[k]; i >= 1; i--) {
            int nextj = k - i;
            if (nextj >= dep) break;

            int nextk = nextj + b[nextj];
            if (dis[nextk] > dis[k] + 1) {
                dis[nextk] = dis[k] + 1;
                pre[nextj] = j;
                q.push({nextj, nextk, nd.steps+1});
            }
        }
        dep = min(dep, k - a[k]);
    }

    return -1;
}

int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    ios::sync_with_stdio(false), cin.tie(0);

    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    for (int i = 1; i <= n;i++)
        cin >> b[i];

    int res = bfs({ n, n });
    cout << res << endl;

    if (res != -1) {
        vector<int> ans;

        for (int i = 1, j = n; i <= res; i++, j = pre[j])
            ans.push_back(pre[j]);
        
        for (int i = res-1; i >= 0; i--)
            cout << ans[i] << ' ';
        cout << endl;
    }
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值