zoukankan      html  css  js  c++  java
  • Codeforces Round #411(Div. 2)——ABCDEF

    30min水掉前面4T,30min尝试读懂EF题,60min划水

    顺便D忘记取膜丢50分,距比赛结束10s时hack失败丢50分...

    从2620掉分到2520,从rank227掉到rank354...血的教训

    真吉尔丢人,题目戳这里

    A. [L,R]中出现次数最多的因子个数

    显然L != R 答案就是2,否则就是 R

    B.仅用'a' 'b' 'c'造字符串,保证不能出现长度为3的回文子串,并尽量少用'c'

    脑补一下发现直接aabbaabbaabb...这样子构造就可以满足了

    C.n个地点标号1-n,从 i 到 j 的花费为 (i + j) % (n + 1)

    出发地点和结束地点自己定,遍历全部n个地点的最小花费

    我们如果直接 1 -> n , 2 -> (n - 1) ...这样子走每次花费就都是0

    然后我们想办法连接他们,发现可以 1 -> n -> 2 -> (n - 1) -> 3 -> (n - 2) ...

    所以answer = (n - 1) / 2

    D.给个只包含'a''b'的字符串,遇'ab'就要换成'bba',求问到不能变换为止的最少变换次数

    我们可以发现

    1.变换后'a'的个数不变,b的个数1个变2个

    2.最后字符串形式一定为bb...bbaa...aa

    于是我们从后往前记录'b'的个数cnt,若遇到一个'a',那么它后面的'b'的个数

    即这个'a'引起的需要变换的次数,即ans += cnt, 且经过cnt次变换后,'b'的个数变成了cnt * 2个

    然后一直往前边扫边算就好了

    #include <bits/stdc++.h>
    
    using namespace std;
    
    char s[1000010];
    
    int main() {
        int n, mod_ = 1e9 + 7;
        long long m = 0, ans = 0;
        scanf("%s", s);
        for(int i = strlen(s) - 1;i >= 0;i --) {
            if(s[i] == 'b') m ++;
            else ans += m, ans %= mod_, m = m * 2 % mod_;
        }
        cout << ans;
        return 0;
    }
    View Code

    E.给一棵n个点的树,树上每个节点都有一个集合,每个集合中包含若干种cream

    由m种cream构成的无向图G,若cream_u与cream_v之间有边

    当且仅当树上存在一点,cream_u与cream_v同时存在该点的集合中

    然后对图G的节点进行染色,使得任意一边连接的两点不同色

    输出最少颜色数和任一方案

    令一重要条件:任一cream存在的树上节点都构成一个联通子图,即

    Vertices which have the i-th (1 ≤ i ≤ m) type of ice cream form a connected subgraph. 

    做题时感觉这棵树存在意义不大...是因为没有明白这个条件的用法

    我们来直观的考虑一下这个条件,如果cream_i 存在于节点u的父亲节点中

    却没有存在于u中,那么显然cream_i 不会再存在于以u为根节点的这个子树中了

    所以我们就可以做了,从根节点开始 dfs,对于当前节点的集合中的所有cream

    如果cream_i 在父亲节点中存在,那么它的颜色号就被标记为不可用

    若不存在,那么就从 1 开始找可用的颜色号给它用就好了

    一个小坑:可能有没有在树上出现过的cream,直接给它染成颜色1就好了

    #include <cstdio>
    #include <vector>
    using namespace std;
    
    const int maxn = 300010;
    
    int n, m, k, d[maxn], g[maxn];
    vector <int> e[maxn], f[maxn];
    
    void dfs(int u, int fa) {
        int i, j = 1;
        for(i = 0;i < e[u].size();i ++)
            if(d[e[u][i]]) 
                g[d[e[u][i]]] = 1;
        for(i = 0;i < e[u].size();i ++)
            if(!d[e[u][i]]) {
                while(g[j]) j ++;
                d[e[u][i]] = j;
                k = max(k, j);
                j ++;
            }
        for(i = 0;i < e[u].size();i ++)
            g[d[e[u][i]]] = 0;
        for(i = 0;i < f[u].size();i ++)
            if(f[u][i] != fa) 
                dfs(f[u][i], u);
    }
    
    int main() {
        int u, v;
        scanf("%d %d", &n, &m);
        for(int i = 1;i <= n;i ++) {
            scanf("%d", &k);
            for(int j = 1;j <= k;j ++)
                scanf("%d", &u), e[i].push_back(u);
        }
        for(int i = 1;i < n;i ++) {
            scanf("%d %d", &u, &v);
            f[u].push_back(v);
            f[v].push_back(u);
        }
        k = 1, dfs(1, -1);
        printf("%d
    ", k);
        for(int i = 1;i <= m;i ++)
            if(!d[i]) 
                d[i] = 1;
        for(int i = 1;i <= m;i ++)
            printf("%d ", d[i]);
        return 0;
     }
    View Code

    F.给你一个森林,然后给你 q 组询问,每组询问包含 u 和 v

    若在节点 u 所在的树和节点 v 所在的树之间随机加一条边的话,求新树的直径的期望值

    (q神给的)解题思路:

    如果只有一组,那么经过一开始的O(n)预处理后,我们可以O(min(siz[u], siz[v]))的时间求出来的

    (如果能想到这个复杂度的话,可以跳过下面2段)

    首先说明我们的预处理,包括每棵树的siz,直径,每个节点所在的树的编号

    以及 len[i] 表示点 i 距离它所在的树中最远点的距离,显然有len[i] < siz[i] ,即肯定小于所在树的siz 

    然后预处理出关于len的权值前缀和之类,预处理基本结束

    然后考虑只有一组询问的话,两棵树加一条边成一棵树

    新的直径要么是原来一棵树的直径,要么是连接的两个点的 len 之和 + 1

    即 old_d  = max(du, dv), new_d = max(len[u] + len[v] + 1, old_d,)

    我们只要处理出有多少组 len[u] + len[v]  + 1> old_d,这些组都算前者,其余都算后者就好了

    这时候就可以用到我们预处理出的权值前缀和了

    对于确定的len[u],可以O(1)求出另一棵树中len[v] > old_d - len[u] - 1的 len[v] 之和

    所以就可以做到O(min(siz[u], siz[v]))了

    那么一组解决了,q组呢,用我们的比格思茅大法来证明复杂度!

    首先令 siz_k = sqrt(n)

    如果 u 和 v 所在的树有一棵树的siz < siz_k,即存在为思茅的话

    那么这次询问的时间就是不超过O(sqrt(n))的

    那么如果两颗树的 siz 均大于呢,即均为比格的话

    因为上述算法取决于 siz 小的树的 siz

    那么考虑最坏情况,两颗树 siz 相同且均大于 siz_k

    那么如果查询所有不同的pair效率是多少呢,  (n / siz) ^ 2 * siz 

    即n ^ 2 / siz,由于 siz > sqrt(n),所以 最坏O(n * sqrt(n))

    当然为了避免同一pair重复查询可以用map来记忆化一下

    综上,考虑map因素,时间O(n * sqrt(n) * logn)

    然而实际表现还是相当不错的!

    #include <bits/stdc++.h>
    
    #define pb push_back
    #define rep(i, j, k) for(int i = j;i < (k + 1);i ++)
    
    using namespace std;
    
    typedef long long ll;
    
    const int maxn = 100010;
    
    bool vis[maxn];
    
    int n, m, q, ks, st, dis;
    
    int cnt, cot, zx[maxn], siz[maxn], tmp[maxn], len[maxn], dlen[maxn];
    
    vector <int> e[maxn];
    vector <ll> f2[maxn], f1[maxn], f3[maxn];
    
    struct node {
        int x, y;
    
        bool operator < (const node &a) const {
            if(x == a.x) return y < a.y;
            return x < a.x;
        }
    };
    
    map <node, double> p;
    
    void dfs1(int x, int f, int d) {
        int y;
        vis[x] = 1, cot ++;
        if(d > dis) dis = d, st = x;
        rep(i, 0, e[x].size() - 1) {
            y = e[x][i];
            if(y == f) continue;
            zx[y] = zx[x];
            dfs1(y, x, d + 1);
         }
    }
    
    void dfs2(int x, int f, int d) {
        int y;
        len[x] = max(len[x], d);
        if(d > dis) dis = d, st = x;
        rep(i, 0, e[x].size() - 1) {
            y = e[x][i];
            if(y != f) dfs2(y, x, d + 1);
         }
    }
    
    void dfs3(int x, int f) {
        int y;
        tmp[len[x]] ++;
        rep(i, 0, e[x].size() - 1) {
            y = e[x][i];
            if(y != f) dfs3(y, x);
         }
    }
    
    int main() {
        ll s;
        node temp;
        int u, v, w, t;
        double ans1, ans2;
        ios::sync_with_stdio(false);
    
        cin >> n >> m >> q;
        ks = (int)sqrt(n + 0.5);
        
        rep(i, 1, m) {
            cin >> u >> v;
            e[u].pb(v), e[v].pb(u);
        }
    
        rep(i, 1, n) if(!vis[i]) {
                cot = 0;
                zx[i] = ++cnt;
                dis = -1, dfs1(i, i, 0), siz[cnt] = cot;
                dis = -1, dfs2(st, st, 0), dlen[cnt] = dis;
                dis = -1, dfs2(st, st, 0);
                dfs3(i, i);
                rep(j, 0, dlen[cnt]) f3[cnt].pb(tmp[j]);s = 0;
                rep(j, 0, dlen[cnt]) f1[cnt].pb(s += tmp[j]);s = 0; 
                rep(j, 0, dlen[cnt]) f2[cnt].pb(s += 1ll * j * tmp[j]);
                rep(j, 0, dlen[cnt]) tmp[j] = 0;
            }
    
        rep(i, 1, q) {
            cin >> u >> v;
            if(zx[u] == zx[v]) puts("-1");
            else {
                ans1 = ans2 = 0;
                u = zx[u], v = zx[v];
                if(siz[u] > siz[v]) swap(u, v);
                if(siz[u] <= ks) {
                    w = max(dlen[u], dlen[v]);
                    rep(j, 0, dlen[u]) 
                        {
                            t = w - j - 1;
                            if(t < 0) ans1 += f3[u][j] * (f2[v][dlen[v]] + f1[v][dlen[v]] * (1 + j));
                            else if(t > dlen[v]) ans1 += f3[u][j] * (f1[v][dlen[v]] * w);
                            else ans1 += f3[u][j] * (f2[v][dlen[v]] - f2[v][t] + (f1[v][dlen[v]] - f1[v][t]) * (1 + j) + f1[v][t] * w);
                        }
                    ans2 = 1.0 * siz[u] * siz[v];
                    printf("%.10f
    ", ans1 / ans2); 
                }
                else {
                    if(p[(node){u, v}]) printf("%.10f
    ", p[(node){u, v}]);
                    else 
                    {
                        w = max(dlen[u], dlen[v]);
                        rep(j, 0, dlen[u]) 
                            {
                                t = w - j - 1;
                                if(t < 0) ans1 += f3[u][j] * (f2[v][dlen[v]] + f1[v][dlen[v]] * (1 + j));
                                else if(t > dlen[v]) ans1 += f3[u][j] * (f1[v][dlen[v]] * w);
                                else ans1 += f3[u][j] * (f2[v][dlen[v]] - f2[v][t] + (f1[v][dlen[v]] - f1[v][t]) * (1 + j) + f1[v][t] * w);
                            }
                        ans2 = 1.0 * siz[u] * siz[v];
                        printf("%.10f
    ", ans1 / ans2); 
                        p[(node){u, v}] = ans1 / ans2;
                    }
                }
            }
        }
    }
    View Code

    代码有点丑,半夜撸了2h的代码非常狗

    下午又调了1h才调出来,谨慎参考,希望能有所帮助

  • 相关阅读:
    layui table表格 表头与内容列错位问题(只有纵向滚动条的情况)
    layui table+复杂表头+合并单元格
    echarts 柱状图
    1-jdk的安装与配置
    变量的解构赋值(对象)
    变量的解构赋值(数组)
    git常用命令
    markdown常用语法
    微信小程序全局/页面配置
    git使用简介(二)
  • 原文地址:https://www.cnblogs.com/ytytzzz/p/6810845.html
Copyright © 2011-2022 走看看