• Educational Codeforces Round 33 (Rated for Div. 2) 题解


    A.每个状态只有一种后续转移,判断每次转移是否都合法即可。

    #include <iostream>
    #include <cstdio>
    using namespace std;
    int a[1001], n;
    bool check(int x){
        if(a[1] == x) return false;
        int l = a[1], r = x, s = 6-a[1]-x;
        for(int i = 2; i <= n; i++){
            if(a[i] == s) return false;
            l = a[i]; r = s; s = 6-l-r;
        }
        return true;
    }
    
    int main()
    {
        cin>>n;
        for(int i = 1; i <= n; i++) cin>>a[i];
        int f = 0;
        if(check(3)) f = 1;
        if(f == 1) printf("YES");
        else printf("NO");
        return 0;
    }

    B.按照题意枚举约数判断即可。

    #include <iostream>
    using namespace std;
    int n;
    bool check(int x){
         for(int i = 1; i <= 100; i++){
            if( ((1<<i) - 1)*(1<<(i-1)) == x) return true;
            if( ((1<<i) - 1)*(1<<(i-1)) > x) return false;
        }
    }
    int a[1010];
    int main()
    {
        int ans = 0, temp = 0, last = 0, L;
        cin>>n;
        for(int i = 1; i <= n; i++){
            if(n%i == 0)
                if(check(i))
                    ans = max(ans, i);
        }
        cout<<ans<<endl;
    }

    C.先用并查集并起来,然后瞎搞即可。

    #include <iostream>
    #include <cstdio>
    using namespace std;
    const int maxn = 1e5 + 100;
    int a[maxn], f[maxn], v[maxn], s[maxn], M[maxn], x, y;
    int find(int x) { return x == f[x] ? f[x] : f[x] = find(f[x]); }
    int main()
    {
        long long ans = 0;
        int n, m;
        cin>>n>>m;
        for(int i = 1; i <= n; i++){
            scanf("%d", &a[i]);
            f[i] = i;
            v[i] = a[i];
        }
        for(int i = 1; i <= m; i++){
            scanf("%d %d", &x, &y);
            f[find(x)] = find(y);
        }
        for(int i = 1; i <= n; i++){
            v[find(i)] = min(v[find(i)], v[i]);
        }
        for(int i = 1; i <= n; i++){
            if(M[find(i)] == 0){
                M[find(i)] = 1;
                ans += (long long)v[find(i)];
            }
        }
        cout<<ans<<endl;
    }

    D.一道题意非常困难的题目orz。

    题意大概就是:给你每天的金钱变化,你可以选择加任意数量的钱,但是需要保证每个时刻的钱数不超过d,而且当金钱变化为0时,此时钱的数量必须非负(check一次)

    最后还是读错题了。

    这道题贪心是对的,先考虑画出价格的折线图。

    在第i天加钱,就相当于抬高i天以后的折线。

    贪心地想,反正加更多的钱总是更优

    所以如果在第i天加钱,就尽量多的加钱

    而能加的钱数就是上限d - Max[i](Max为从i到n的后缀),如果比这个还多,那么后面必定会超

    所以就在每个需要加钱的位置都贪心地加钱即可。

    #include <iostream>
    #include <cstdio>
    using namespace std;
    const int maxn = 1e5 + 100;
    int a[maxn], n;
    long long b[maxn], Max[maxn], d;
    int main()
    {
        cin>>n>>d;
        for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
        b[0] = 0;
        for(int i = 1; i <= n; i++) b[i] = b[i-1] + a[i];
        Max[n] = b[n];
        for(int i = n-1; i >= 1; i--) Max[i] = max(b[i], Max[i+1]);
        int t = 0, f = 0;
        if(Max[1] > d){
            f = 1;
        } else {
            long long h = 0;
            for(int i = 1; i <= n; i++){
                if(a[i] == 0 && b[i] + h < 0){
                    h = d - Max[i];
                    t++;
                    if(b[i] + h < 0) { f = 1; break; }
                }
            }
        }
        if(f){
            printf("-1");
        } else printf("%d", t);
        return 0;
    }

    E.给你一个数x,你需要把它拆成y个数的乘积,只要对应位置的yi有一个不同,方案就是不同的,问有多少种方案(负数也算)

    首先考虑只有正数。

    把x质因数拆分,然后对于每个质因数

    你需要把它分配个y个数,比如24 = 3*2^3

    其中就需要把3个2分配给y个数,实际上就是y个不同的盒子,3个球,问有多少种方案

    答案就是C(y+3-1, y-1)

    然后每个质因数乘起来就可以了。

    如果是负数,那么其实就是每个正数的方案选出2个变成负数

    就是C(n, 0) + C(n, 2) + ....  = 2^(n-1)

    最后都乘起来就可以了。

    这题很蠢的是数组越界了,因为n+m大于1e6,但是没有预处理到(以及找质因数的写法一定要注意)

    #include <iostream>
    #include <vector>
    #include <cstdio>
    #define mp make_pair
    #define fi first
    #define se second
    using namespace std;
    vector< pair<int, int> > V;
    const int MOD = 1e9 + 7;
    typedef long long LL;
    LL f[1100010], invf[1100010];
    LL mypow(LL a, LL b){
        LL ans = 1; for(; b; b >>= 1, (a *= a) %= MOD) if(b&1) (ans *= a) %= MOD; return ans;
    }
    LL C(LL n, LL m){
        return f[n]*invf[m]%MOD*invf[n-m]%MOD;
    }
    int T, x, y;
    int main()
    {
        cin>>T;
        f[0] = 1;
        for(int i = 1; i <= 1100000; i++) f[i] = f[i-1]*i%MOD;
        invf[1100000] = mypow(f[1100000], MOD-2);
        for(int i = 1100000-1; i >= 0; i--) invf[i] = (invf[i+1]*(i+1))%MOD;
        while(T--){
            scanf("%d %d", &x, &y);
            int t = x;
            long long ans = 1;
            for(int i = 2; i*i <= x; i++){
                if(t % i == 0){
                    int temp = 0;
                    while(t % i == 0) temp++, t /= i;
                    (ans *= C(temp+y-1, y-1) ) %= MOD;
                }
            }
            if(t != 1) (ans *= y) %= MOD;
            (ans *= mypow(2, y-1)) %= MOD;
            printf("%I64d
    ", ans);
        }
        return 0;
    }

    F.给定一棵树,每次询问x构成的子树内,距离x结点小于等于k的点中值最小的是多少。强制在线

    这题我是用可持久化线段树+维护dfs序做的,复杂度是nlogn。不过也有很暴力的线段树维护dfs序nlognlogn做法

    具体思想就是可持久化线段树的结点对应是dfs序

    插入的时间是按深度排序。

    那么询问x,k

    就是问插入时间从1~deep[x]+k所构成的树中,x的子树中结点最小的值是多少。

    然后维护dfs序,就是查询tree(deep[x] + k, ein[x], eout[x])这个区间的值。

    大概就是这样,没什么很坑的地方。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    using namespace std;
    const int maxn = 2e5 + 500;
    struct Node{
        Node *l, *r;
        int v;
        void maintain(){
            v = min(l->v, r->v);
        }
    }pool[maxn*16], *root[maxn], *null;
    int pooltot = 0;
    Node *newnode(){
        Node* temp = &pool[pooltot++];
        temp->l = temp->r = null; temp->v = 1e9; //
        return temp;
    }
    void init(){
        null = new Node();
        null->l = null->r = null;
        null->v = 1e9; //
    }
    void Insert(Node *&o, Node *o2, int l, int r, int k, int v){
        if(o == null) o = newnode();
        if(l == r) { o->v = min(v, o2->v); return; } //
        int mid = (l+r)/2;
        if(k <= mid) {
            Insert(o->l, o2->l, l, mid, k, v);
            o->r = o2->r;
        } else {
            Insert(o->r, o2->r, mid+1, r, k, v);
            o->l = o2->l;
        }
        o->maintain();
    }
    int Query(Node *o, int l, int r, int L, int R){
        if(o == null) return 1e9; //
        if(L <= l && r <= R) return o->v;
        int mid = (l+r)/2, ans = 1e9; //
        if(L <= mid) ans = min(ans, Query(o->l, l, mid, L, R)); //
        if(R > mid) ans = min(ans, Query(o->r, mid+1, r, L, R)); //
        return ans;
    }
    int tot = 0, Maxd, timer = 0;
    int ein[maxn], deep[maxn], eout[maxn], a[maxn], lastd[maxn];
    vector<int> D[maxn], G[maxn];
    void dfs(int x, int fa, int d){
        ein[x] = ++tot;
        deep[x] = d;
        Maxd = max(d, Maxd);
        D[d].push_back(x);
        for(auto to : G[x]){
            if(to == fa) continue;
            dfs(to, x, d+1);
        }
        eout[x] = tot;
    }
    int n, r, x, y, q;
    int main(){
        init();
        cin>>n>>r;
        for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for(int i = 1; i < n; i++){
            scanf("%d %d", &x, &y);
            G[x].push_back(y);
            G[y].push_back(x);
        }
        dfs(r, r, 1);
        for(int i = 0; i <= n + 100; i++) root[i] = newnode();
        for(int i = 0; i <= Maxd; i++){
            for(auto x : D[i]){
                Insert(root[timer+1], root[timer], 1, tot, ein[x], a[x]);
                timer++;
            }
            lastd[i] = timer;
        }
        scanf("%d", &q);
        int last = 0;
        while(q--){
            scanf("%d %d", &x, &y);
            x = (x+last)%n + 1;
            y = (y+last)%n;
            printf("%d
    ", last = Query(root[lastd[min(Maxd, deep[x]+y)]], 1, tot, ein[x], eout[x]));
        }
    }
  • 相关阅读:
    研究生数学建模历年题目汇总
    【20220902】成年人的美好
    【20220831】恶梦
    【20220827】连岳摘抄
    【20220903】连岳摘抄
    【20220904】勇气之笔
    【20220905】珍惜时光
    【20220901】连岳摘抄
    【20220830】哺乳
    【力扣 056】123. 买卖股票的最佳时机 III
  • 原文地址:https://www.cnblogs.com/Saurus/p/7891315.html
Copyright © 2020-2023  润新知