zoukankan      html  css  js  c++  java
  • 2020牛客暑期多校训练营(第七场)

    Contest Info


    传送门

    Solved A B C D E F G H I J
    6 / 10 - O O O - - - O O O
    • O 在比赛中通过
    • Ø 赛后通过
    • ! 尝试了但是失败了
    • - 没有尝试

    Solutions


    B. Mask Allocation

    类似于欧几里得算法的想法去构造即可,这样可取到最大值。

    Code
    // Author : heyuhhh
    // Created Time : 2020/08/01 12:54:54
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
    void run() {
        int n, m;
        cin >> n >> m;
        vector<int> ans;
        while (n) {
            if (n < m) swap(n, m);
            for (int i = 1; i <= m; i++) {
                ans.push_back(m);
            }
            n -= m;
        }
        sort(all(ans));
        reverse(all(ans));
        cout << sz(ans) << '
    ';
        for (auto it : ans) {
            cout << it << ' ';
        }
        cout << '
    ';
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        int T; cin >> T; while(T--)
        run();
        return 0;
    }
    

    C. A National Pandemic

    题意:
    给定一颗无根树,初始每个结点的权值为(0)
    然后有以下三种操作:

    • 选定(x),然后每个点权值加上(w-dist(x,y))
    • (F(x)=min(F(x),0))
    • 询问(F(x))

    思路:
    稍加思考可以发现,二操作就是卖萌的,我们记录一个delta值就行。
    考虑如何处理一操作:(w-dist(x,y)=w-(deep(x)+deep(y)-2lca(x,y)))
    那么(w,deep[x],deep[y])部分我们用全局变量标记一下即可,主要是处理(lca)部分。
    这一部分我们考虑差分来处理,即从每一个(y)点出发跳到祖先能得到(-2lca(x,y)),所以只需要把(x)到祖先这条链权值都加上(2)即可。
    用树剖来处理的话时间复杂度为(O(nlog^2n))
    代码如下:

    Code
    // Author : heyuhhh
    // Created Time : 2020/08/02 18:04:12
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    void err(int x) {cerr << x;}
    void err(long long x) {cerr << x;}
    void err(double x) {cerr << x;}
    void err(char x) {cerr << '"' << x << '"';}
    void err(const string &x) {cerr << '"' << x << '"';}
    void _print() {cerr << "]
    ";}
    template<typename T, typename V>
      void err(const pair<T, V> &x) {cerr << '{'; err(x.first); cerr << ','; err(x.second); cerr << '}';}
    template<typename T>
      void err(const T &x) {int f = 0; cerr << '{'; for (auto &i: x) cerr << (f++ ? "," : ""), err(i); cerr << "}";}
    template <typename T, typename... V>
      void _print(T t, V... v) {err(t); if (sizeof...(v)) cerr << ", "; _print(v...);}
    #ifdef Local
    #define dbg(x...) cerr << "[" << #x << "] = ["; _print(x)
    #else
    #define dbg(x...)
    #endif
    //head
    const int N = 1e5 + 5;
    
    vector<int> G[N];
    int n, m;
    // 注意bson的初始化,其余可以自动初始化
    // 注意每个点实际值为dfn[x]
    int sz[N], deep[N], bson[N], ff[N];
    int top[N], dfn[N], T;
    void dfs(int u, int fa) {
        deep[u] = deep[fa] + 1;
        sz[u] = 1;
        ff[u] = fa;
        int Max = -1;
        for (auto v : G[u]) {
            if (v != fa) {
                dfs(v, u);
                sz[u] += sz[v];
                if (sz[v] > Max) {
                    Max = sz[v];
                    bson[u] = v;
                }
            }
        }
    }
    
    void dfs(int u, int fa, int topf) {
        dfn[u] = ++T;
        top[u] = topf;
        if (bson[u] != 0) {
            dfs(bson[u], u, topf);
        }
        for (auto v : G[u]) {
            if (v != fa && v != bson[u]) {
                dfs(v, u, v);
            }
        }
    }
    
    ll sumv[N << 2], lz[N << 2];
    
    //区间加
    void tag(int o, int l, int r, ll v) {
        sumv[o] += 1ll * (r - l + 1) * v;
        lz[o] += v;
    }
    
    void push_up(int o) {
        sumv[o] = sumv[o << 1] + sumv[o << 1|1];
    }
    
    void push_down(int o, int l, int r) {
        if(lz[o] != 0) {
            int mid = (l + r) >> 1;
            tag(o << 1, l, mid, lz[o]);
            tag(o << 1|1, mid + 1, r, lz[o]);
            lz[o] = 0;   
        }
    }
    
    void build(int o, int l, int r) {
        lz[o] = 0;
        if(l == r) {
            sumv[o] = 0;
            return;
        }
        int mid = (l + r) >> 1;
        build(o << 1, l, mid), build(o << 1|1, mid + 1, r);
        push_up(o);
    }
    
    void update(int o, int l, int r, int L, int R, int v) {
        if(L <= l && r <= R) {
            tag(o, l, r, v);
            return;
        }   
        push_down(o, l, r);
        int mid = (l + r) >> 1;
        if(L <= mid) update(o << 1, l, mid, L, R, v);
        if(R > mid) update(o << 1|1, mid + 1, r, L, R, v);
        push_up(o);
    }
    
    ll query(int o, int l, int r, int L, int R) {
        if(L <= l && r <= R) {
            return sumv[o];
        }
        push_down(o, l, r);
        int mid = (l + r) >> 1;
        ll res = 0;
        if(L <= mid) res += query(o << 1, l, mid, L, R);
        if(R > mid) res += query(o << 1|1, mid + 1, r, L, R);
        return res;
    }
    
    ll add[N];
    ll cnt, sumx;
    
    ll query(int x) {
        ll res = 0;
        int t = x;
        while (x != 0) {
            res += query(1, 1, n, dfn[top[x]], dfn[x]);
            x = ff[top[x]];
        }
        return res + add[t] - 1ll * cnt * deep[t] + sumx;
    }
    
    void modify(int x) {
        while (x != 0) {
            update(1, 1, n, dfn[top[x]], dfn[x], 2);
            x = ff[top[x]];
        }
    }
    
    
    
    void run() {
        cin >> n >> m;
        for (int i = 1; i <= n; i++) {
            G[i].clear();
            bson[i] = 0;
            add[i] = 0;
        }
        T = sumx = cnt = 0;
        for (int i = 1; i < n; i++) {
            int u, v;
            cin >> u >> v;
            G[u].push_back(v);
            G[v].push_back(u);
        }
        dfs(1, 0);
        dfs(1, 0, 1);
        build(1, 1, n);
        while (m--) {
            int op;
            cin >> op;
            if (op == 1) {
                int w, x;
                cin >> x >> w;
                ++cnt;
                sumx += w - deep[x];
                modify(x);
            } else if (op == 2) {
                int x;
                cin >> x;
                ll res = query(x);
                if (res > 0) {
                    add[x] -= res;
                }
            } else {
                int x;
                cin >> x;
                ll res = query(x);
                cout << res << '
    ';
            }
        }
    }
    
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        int T; cin >> T; while(T--)
        run();
        return 0;
    }
    

    也可以直接用点分树来维护距离,具体来说就是(x,y)之间的距离就是两个点在点分树中到他们lca的距离之和,因为树高为(logn),所以每次修改一个点过后,只会影响其余每个点到它的logn种路径。然后也是类似于差分的思想来计算答案。即当(y ightarrow f(y))时,我们需要统计来自另外子树的贡献,减去来自(y)这颗子树的贡献。所以修改值时要在每个父亲结点打个正贡献的标记,然后在他们父亲处打个负贡献标记即可。
    这样时间复杂度为(O(nlogn))
    直接copy别人的代码qaq。

    Code
    #include<bits/stdc++.h>
     
    using namespace std;
     
    #define fi first
    #define se second
    #define pb push_back
    #define mp make_pair
    #define LC k<<1
    #define RC k<<1|1
    #define tm tttadt
     
    typedef long long LL;
    const int N=510000;
    const int M=1100000;
    const LL mod=1e9+7;
     
     
    int T,n,m;
    LL delta[N],sumw;
    struct point_tree
    {
        vector<int> ch[N];
        vector<int> g[N];
        int f[N],sum,n,son[N],pp[N],nxt,root;
        int up[N],dis[20][N],dep[N];
        LL s1[20][N],s2[20][N];
        void getroot(int x,int fa)
        {
            son[x]=1,f[x]=0;
            for (int i=0;i<g[x].size();i++)
                if (!pp[g[x][i]]&&g[x][i]!=fa)
                {
                    getroot(g[x][i],x);
                    son[x]+=son[g[x][i]];
                    f[x]=max(f[x],son[g[x][i]]);
                }
            f[x]=max(f[x],sum-son[x]);
            if (f[x]<f[nxt]) nxt=x;
        }
        void dfs(int x,int fa,int depth)
        {
            if (fa) dis[depth][x]=dis[depth][fa]+1;
            else dis[depth][x]=0;
            for (int i=0;i<g[x].size();i++)
                if (!pp[g[x][i]]&&g[x][i]!=fa) dfs(g[x][i],x,depth);
        }      
        void work(int x,int fa,int depth)
        {
            dep[x]=depth;
            dfs(x,0,depth);
            up[x]=fa;
            pp[x]=1;
            for (int i=0;i<g[x].size();i++)
                if (!pp[g[x][i]])
                {
                    nxt=0,sum=son[g[x][i]];
                    getroot(g[x][i],0);
                    ch[x].pb(nxt);
                    work(nxt,x,depth+1);
                }
        }
        void change(int x)
        {
            int cur=x,depth=dep[x],last=0;
            while (cur)
            {
                s1[depth][cur]+=dis[depth][x];
                s2[depth][cur]+=1;
                if (last) s1[depth][last]-=dis[depth][x],s2[depth][last]-=1;
                last=cur;
                cur=up[cur];
                depth--;
            }
        }
        LL ask(int x)
        {
            LL res=sumw-delta[x];
            int cur=x,depth=dep[x],last=0;
            while (cur)
            {
                res-=s1[depth][cur];
                res-=s2[depth][cur]*dis[depth][x];
                if (last) res-=s1[depth][last],res-=s2[depth][last]*dis[depth][x];
                last=cur;
                cur=up[cur];
                depth--;
            }
            return res;
        }
        void init()
        {
            for (int i=1;i<=n;i++)
                g[i].clear(),pp[i]=0;
            memset(s1,0,sizeof(s1));
            memset(s2,0,sizeof(s2));
            for (int i=1;i<n;i++)
            {
                int x,y;
                scanf("%d %d",&x,&y);
                g[x].pb(y);
                g[y].pb(x);
            }
            f[0]=sum=n;
            nxt=0;
            getroot(1,0);
            root=nxt;
            work(root,0,0);
        }
    }A;
    int main()
    {
        scanf("%d",&T);
        while (T--)
        {
            scanf("%d %d",&n,&m);
            sumw=0;
            A.n=n;
            A.init();
            for (int i=1;i<=n;i++)
                delta[i]=0;
            while (m--)
            {
                int op;
                scanf("%d",&op);
                if (op==1)
                {
                    int x,w;
                    scanf("%d %d",&x,&w);
                    A.change(x);
                    sumw+=w;
                }
                else if (op==2)
                {
                    int x;
                    scanf("%d",&x);
                    LL val=A.ask(x);
                    if (val>0) delta[x]+=val;
                }
                else
                {
                    int x;
                    scanf("%d",&x);
                    LL val=A.ask(x);
                    printf("%lld
    ",val);
                }
            }
        }
        return 0;
    }
    

    D. Fake News

    签到。

    Code
    // Author : heyuhhh
    // Created Time : 2020/08/01 12:06:53
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
    void run() {
        ll n;
        cin >> n;
        if (n == 1 || n == 24) {
            cout << "Fake news!" << '
    ';
        } else {
            cout << "Nobody knows it better than me!" << '
    ';
        }
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        int T; cin >> T; while (T--)
        run();
        return 0;
    }
    

    H. Dividing

    数论分块即可。

    I. Valuable Forests

    题意:
    (n,nleq 5000)个点生成一个森林,森林的贡献为(sum (d(i))^2,d(i))代表每个结点的度数。
    问所有情况的贡献之和为多少。

    思路:
    观察范围首先可以明确复杂度应该是(O(n^2))的。
    因为这是树上计数问题,那么我们容易想到prufer定理。
    首先有:(n)个点组成的有标号无根树,其个数为(n^{n-2})
    然后(n)个点组成树的度数贡献之和为(displaystylesum_{i=1}^nsum_{d=1}^{n-1}d^2{n-2choose d-1}(n-1)^{n-2-d+1})。这一步也是根据prufer定理,因为定理内容则是将一颗树与一个序列一一对应。
    那么剩下的便是一些基本的图论上面dp的内容了,我们可以(O(n^2))dp出(f(n),F(n)),分别表示(n)个点的森林有多少种情况,以及(n)个点的森林最终的答案为多少。这里dp时有一个常见的思路,就是我们枚举(i)时,枚举(i)所在的环的大小,如果直接枚举环的大小可能会出问题。
    另外还要注意算(F)时,要分别考虑两部分的答案对另一部分贡献的影响。
    细节见代码:

    Code
    // Author : heyuhhh
    // Created Time : 2020/08/05 20:10:05
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 5000 + 5;
    int MOD;
    
    int qpow(ll a, ll b) {
        ll res = 1;
        while(b) {
            if(b & 1) res = res * a % MOD;
            a = a * a % MOD;
            b >>= 1;   
        }
        return res;   
    }
    int fac[N], inv[N];
    void init() {
        fac[0] = 1;
        for(int i = 1; i < N; i++) fac[i] = 1ll * fac[i - 1] * i % MOD;
        inv[N - 1] = qpow(fac[N - 1], MOD - 2);
        for(int i = N - 2; i >= 0; i--) inv[i] = 1ll * inv[i + 1] * (i + 1) % MOD;
    }
    int C(int n, int m) {
        return 1ll * fac[n] * inv[m] % MOD * inv[n - m] % MOD;
    }
    
    int ans[N];
    int f[N], A[N], a[N];
    
    void run() {
        int T;
        cin >> T >> MOD;
        init();
        a[1] = 1;
        for (int i = 2; i < N; i++) {
            a[i] = qpow(i, i - 2);
        }
        
        f[0] = 1;
        for (int i = 1; i < N; i++) {
            for (int j = 0; j < i; j++) {
                f[i] = (f[i] + 1ll * C(i - 1, j) * f[i - j - 1] % MOD * a[j + 1] % MOD) % MOD;
            }
        }
        
        A[1] = 0;
        for (int i = 2; i < N; i++) {
            for (int d = 1; d < i; d++) {
                A[i] = (A[i] + 1ll * i * C(i - 2, d - 1) % MOD * d % MOD * d % MOD * qpow(i - 1, i - 2 - d + 1) % MOD) % MOD;
            }
        }
        
    
        ans[1] = 0;
        for (int i = 2; i < N; i++) {
            for (int j = 0; j < i; j++) {
                ans[i] = (ans[i] + 1ll * C(i - 1, j) * ((1ll * f[i - j - 1] * A[j + 1] % MOD 
                        + 1ll * ans[i - j - 1] * a[j + 1] % MOD) % MOD) % MOD) % MOD;
            }
        }
        while (T--) {
            int n;
            cin >> n;
            cout << ans[n] << '
    ';
        }
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        run();
        return 0;
    }
    

    J. Pointer Analysis

    把题意理解清楚过后按照要求传递闭包即可,一开始只求了一次wa飞了,后来多求几次闭包就A了qaq

    Code
    // Author : heyuhhh
    // Created Time : 2020/08/01 14:33:39
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    void err(int x) {cerr << x;}
    void err(long long x) {cerr << x;}
    void err(double x) {cerr << x;}
    void err(char x) {cerr << '"' << x << '"';}
    void err(const string &x) {cerr << '"' << x << '"';}
    void _print() {cerr << "]
    ";}
    template<typename T, typename V>
      void err(const pair<T, V> &x) {cerr << '{'; err(x.first); cerr << ','; err(x.second); cerr << '}';}
    template<typename T>
      void err(const T &x) {int f = 0; cerr << '{'; for (auto &i: x) cerr << (f++ ? "," : ""), err(i); cerr << "}";}
    template <typename T, typename... V>
      void _print(T t, V... v) {err(t); if (sizeof...(v)) cerr << ", "; _print(v...);}
    #ifdef Local
    #define dbg(x...) cerr << "[" << #x << "] = ["; _print(x)
    #else
    #define dbg(x...)
    #endif
    //head
    const int N = 1000 + 5;
      
    int mp[N][N];
      
    void Floyd(int n) {
        for (int k = 0; k < n; k++) {
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    mp[i][j] |= (mp[i][k] & mp[k][j]);
                }
            }
        }
    }
      
    void run() {
        int n;
        cin >> n;
        vector<string> el(n), er(n);
        for (int i = 0; i < n; i++) {
            string t;
            cin >> el[i] >> t >> er[i];
        }
        auto is_big = [&](char x) {
            return 'A' <= x && x <= 'Z';
        };
        auto trans_big = [&](char x) {
            return x - 'A';
        };
        auto trans_samll = [&](char x) {
            return x - 'a' + 26;
        };
        for (int i = 0; i < n; i++) {
            if (el[i].length() == 1 && er[i].length() == 1) {
                int u, v;
                if (is_big(el[i][0])) {
                    u = trans_big(el[i][0]);
                } else {
                    u = trans_samll(el[i][0]);
                }
                if (is_big(er[i][0])) {
                    v = trans_big(er[i][0]);
                } else {
                    v = trans_samll(er[i][0]);
                }
                // dbg(u, v);
                mp[u][v] = 1;
            }
        }
        int tot = 52;
        for (int i = 0; i < N; i++) {
            mp[i][i] = 1;
        }
        Floyd(tot);
     
        int cnt = 10;
        vector<vector<int>> val(52, vector<int>(26, -1));
     
        while (cnt--) {
            for (int i = 0; i < n; i++) {
                int l1 = el[i].length(), l2 = er[i].length();
                if (l1 == 1 && l2 == 1) continue;
                if (l2 == 1) {
                    int u = trans_big(el[i][0]);
                    int v = trans_big(er[i][0]);
                    int t = trans_samll(el[i][2]) - 26;
                    for (int j = 26; j < 52; j++) {
                        if (mp[u][j]) {
                            if (val[j][t] == -1) val[j][t] = tot++;
                            mp[val[j][t]][v] = 1;
                        }
                    }
                }
            }
            Floyd(tot);
            for (int i = 0; i < n; i++) {
                int l1 = el[i].length(), l2 = er[i].length();
                if (l1 == 1 && l2 == 1) continue;
                if (l1 == 1) {
                    int u = trans_big(el[i][0]);
                    int v = trans_big(er[i][0]);
                    int t = trans_samll(er[i][2]) - 26;
                    for (int j = 26; j < 52; j++) {
                        if (mp[v][j]) {
                            // dbg(t, u, val[j][t]);
                            if (val[j][t] == -1) val[j][t] = tot++;
                            mp[u][val[j][t]] = 1;
                        }
                    }
                }
            }
            Floyd(tot);       
        }
     
     
        vector<vector<char>> ans(26);
        for (int i = 0; i < 26; i++) {
            for (int j = 26; j < 52; j++) {
                if (mp[i][j]) {
                    ans[i].push_back('a' + (j - 26)); 
                }
            }
            sort(all(ans[i]));
        }
        for (int i = 0; i < 26; i++) {
            cout << char('A' + i) << ": ";
            for (auto& it : ans[i]) {
                cout << it;
            }
            cout << '
    ';
        }
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        run();
        return 0;
    }s
    
  • 相关阅读:
    Ubuntu 17 安装sublime
    ubuntu17 设置python3为默认及一些库的安装
    Java中内存分析(一)
    我的学习JavaEE路线
    我爱学习……
    HDU 4602
    K-special Tables
    Gym 100712A - Who Is The Winner
    UVA 1583
    水题 UVA 1586
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/13456520.html
Copyright © 2011-2022 走看看