zoukankan      html  css  js  c++  java
  • 《Educational Codeforces Round 112 (Rated for Div. 2)》

    这场前面几题感觉都不是很难。

    A:很显然很大的时候都用最大的来塞就行了,对于较小的时候用背包计算下最优的方案。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL,int> pii;
    const int N = 1e6 + 1;
    const int M = 1e5;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    
    LL dp[N];
    void init() {
        memset(dp,0x3f3f3f3f,sizeof(dp));
        dp[0] = 0;
        dp[1] = dp[2] = dp[3] = dp[4] = dp[5] = dp[6] = 15;
        dp[7] = 20,dp[8] = 20,dp[9] = 25,dp[10] = 25;
        for(int i = 11;i < N;++i) {
            dp[i] = min(dp[i],dp[i - 6] + 15);
            dp[i] = min(dp[i],dp[i - 8] + 20);
            dp[i] = min(dp[i],dp[i - 10] + 25);
        }
    }
    int main() {
        init();
        int ca;scanf("%d",&ca);
        int up = 1e6;
        LL ma = M * 25;
        while(ca--) {
            LL n;scanf("%lld",&n);
            if(n > up) {
                LL x = n / up;
                LL y = n - x * up;
                LL ans = ma * x + dp[y];
                printf("%lld
    ",ans);
            }
            else printf("%lld
    ",dp[n]);
        }
    
    
    
        //system("pause");
        return 0;
    }
    View Code

    B:显然四个角落代表四种最优情况。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL,int> pii;
    const int N = 1e6 + 1;
    const int M = 1e5;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    
    int main() {
        int ca;scanf("%d",&ca);
        while(ca--) {
            int W,H;scanf("%d %d",&W,&H);
            int x1,y1,x2,y2;scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
            int w,h;scanf("%d %d",&w,&h);
            int w1 = x2 - x1,h1 = y2 - y1;
            int lenw = w1 + w,lenh = h1 + h;
            if(lenw > W && lenh > H) printf("-1
    ");
            else {
                int dis1 = 0;
                if(x1 < w) dis1 = w - x1;
                if(lenw > W) dis1 = INF;
                int dis2 = 0;
                if(x2 > W - w) dis2 = x2 - (W - w);
                if(lenw > W) dis2 = INF;
                int dis3 = 0;
                if(y1 < h) dis3 = h - y1;
                if(lenh > H) dis3 = INF;
                int dis4 = 0;
                if(y2 > H - h) dis4 = y2 - (H - h);
                if(lenh > H) dis4 = INF;
               // printf("d1 is %d d2 is %d d3 is %d d4 is %d
    ",dis1,dis2,dis3,dis4);
                double ans = min(1.0 * dis1,1.0 * dis2);
                ans = min(ans,1.0 * dis3);
                ans = min(ans,1.0 * dis4);
                printf("%.8f
    ",ans);
            }
    
        }
    
       // system("pause");
        return 0;
    }
    View Code

    C:感觉比A都简单。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL,int> pii;
    const int N = 1e5 + 1;
    const int M = 1e5;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e18
    #define dbg(ax) cout << "now this num is " << ax << endl;
    
    int a[5][N];
    LL sum[5][N];
    int main() {
        int ca;scanf("%d",&ca);
        while(ca--) {
            memset(sum,0,sizeof(sum));
            int m;scanf("%d",&m);     
            for(int i = 1;i <= 2;++i)
                for(int j = 1;j <= m;++j) scanf("%d",&a[i][j]),sum[i][j] = sum[i][j - 1] + a[i][j];
            LL ans = INF;
            for(int i = 1;i <= m;++i) {
                LL ma1 = sum[1][m] - sum[1][i];
                LL ma2 = sum[2][i - 1];
                ans = min(ans,max(ma1,ma2));
            }
            printf("%lld
    ",ans);
        }
    
        //system("pause");
        return 0;
    }
    View Code

    D:分析题意可以发现,满足条件的字符串只有abc三种交叉着来。

    那么我们可以发现,如果开头的两个字符固定,那么后面的所有字符也就固定了。

    也就是说字符串只有ab,ac,ba,bc,ca,cb六种开头的形式,前缀和一下,取最小的即可。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL,int> pii;
    const int N = 2e5 + 5;
    const int M = 1e5;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    
    int n,m;
    string s;
    LL pre[10][N];
    char cal(char a,char b) {
        if(a == 'a' && b == 'b' || a == 'b' && b == 'a') return 'c';
        if(a == 'a' && b == 'c' || a == 'c' && b == 'a') return 'b';
        if(a == 'b' && b == 'c' || a == 'c' && b == 'b') return 'a';
    }
    void solve(int id,char a,char b) {
        char c1 = a,c2 = b;
        if(s[0] != a) pre[id][1] = 1;
        pre[id][2] = pre[id][1];
        if(s[1] != b) pre[id][2]++;
        for(int i = 3;i <= n;++i) {
            char now = cal(c1,c2);
            pre[id][i] = pre[id][i - 1];
            if(s[i - 1] != now) pre[id][i]++;
            c1 = c2,c2 = now;
        }
    }
    int main() {
        scanf("%d %d",&n,&m);
        cin >> s;
        solve(1,'a','b');
        solve(2,'a','c');
        solve(3,'b','a');
        solve(4,'b','c');
        solve(5,'c','a');
        solve(6,'c','b');
        while(m--) {
            int L,r;scanf("%d %d",&L,&r);
            if(L == r) printf("0
    ");
            else if(r - L == 1) printf("%d
    ",s[L - 1] == s[r - 1] ? 1 : 0);
            else {  
                LL ans = INF;
                for(int i = 1;i <= 6;++i) ans = min(ans,pre[i][r] - pre[i][L - 1]);
                printf("%lld
    ",ans);
            }
        }
    
       // system("pause");
        return 0;
    }
    /*
    5 10
    aaaac
    1 5
    
    */
    View Code

    E:这个题一开始的想法是在按线段左界排 ,在线段树上维护dp,但是如果用set维护答案,那么复杂度会过高。

    正解:考虑尺取,这个真的很巧妙。

    我们考虑维护一个下界对应的最小上界,所以我们将所有线段按权值来排序,然后尺取去加上线段,当满足覆盖到所有点之后。

    说明我们维护的这段区间是以当前左界为下界的最小上界,这很显然。

    对于所有点都被覆盖的情况,我们通过线段树去统计每个点被覆盖的次数,然后查询最小值即可,如果最小值 > 0,说明满足。

    这里还有个细节就是,他这里其实是要线段覆盖,也就是说明每个点之间要有边连起来,那么我们就可以把每次维护的右端点看成是断开的。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    const int N = 3e5 + 5;
    const int M = 1e6 + 5;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    
    int n,m;
    struct PT{
        int L,r,w;
        bool operator < (const PT &a) const {
            return w < a.w;
        }
    }p[N];
    struct Node{int L,r,tag,micnt;}node[M << 2];
    void Pushup(int idx) {
        node[idx].micnt = min(node[idx << 1].micnt,node[idx << 1 | 1].micnt);
    }
    void Pushdown(int idx) {
        if(node[idx].tag != 0) {
            node[idx << 1].micnt += node[idx].tag;
            node[idx << 1 | 1].micnt += node[idx].tag;
            node[idx << 1].tag += node[idx].tag;
            node[idx << 1 | 1].tag += node[idx].tag;
            node[idx].tag = 0;
        }
    }
    void build(int L,int r,int idx) {
        node[idx].L = L,node[idx].r = r,node[idx].micnt = node[idx].tag = 0;
        if(L == r) {
            return ;
        }
        int mid = (L + r) >> 1;
        build(L,mid,idx << 1);
        build(mid + 1,r,idx << 1 | 1);
        Pushup(idx);
    }
    void update(int L,int r,int idx,int val) {
        if(node[idx].L >= L && node[idx].r <= r) {
            node[idx].micnt += val;
            node[idx].tag += val;
            return ;
        }
        Pushdown(idx);
        int mid = (node[idx].L + node[idx].r) >> 1;
        if(mid >= L) update(L,r,idx << 1,val);
        if(mid < r) update(L,r,idx << 1 | 1,val);
        Pushup(idx);
    }
    int main() {
        scanf("%d %d",&n,&m);
        for(int i = 1;i <= n;++i) scanf("%d %d %d",&p[i].L,&p[i].r,&p[i].w);
        sort(p + 1,p + n + 1);
        int ans = INF;
        if(m == 1) printf("0
    ");
        else {
            build(1,m - 1,1);
            int L = 1,r = 1;
            if(p[1].L != p[1].r) update(p[1].L,p[1].r - 1,1,1);
            while(L <= r && r <= n) {
                if(node[1].micnt > 0) {
                    ans = min(ans,p[r].w - p[L].w);
                    if(ans == 0) break;
                    if(p[L].L != p[L].r) update(p[L].L,p[L].r - 1,1,-1);
                    L++;
                }
                else {
                    r++;
                    if(p[r].L != p[r].r) update(p[r].L,p[r].r - 1,1,1);
                }
            }
            printf("%d
    ",ans);
        }
    
        //system("pause");
        return 0;
    }
    View Code

    F:这题很不错我觉得,而且解法好像有很多。

    首先,我们考虑什么情况下可以加边。

    如果该条边是两个不同连通块的边,那么很显然可以加入,这里用并查集判断即可。

    这时我们可以发现一个很显然的结论,如果一条边能连通两个简单环,那么一定不能加入,因为另外两个简单环的异或和一定是权值一样的(因为都异或这条边 = 1)。

    那么加入这条边后,两个简单环组成的大环异或和肯定 = 0。

    也就是说对于一条边,它最多只能在一个简单环中。那么很显然是叫我们去维护一个仙人掌图。

    我们考虑这个树形图。

    对于这棵树,如果我们加入的这条边,连通的全部都是树边,那么就满足。如果连通的有非树边,那么就不满足。

    我们可以考虑虚加入这条边,也就是计算上但是不真正加入到图中,那么我们维护的就会始终是一棵树。

    所以我们需要支持一种操作,对所有非树边打上标记,且一次性查询一段树上的异或和。

    对于一段树上异或和的查询,我们可以维护从树根开始的一个异或和。

    那么对于树上任意两点的异或和  = dp[u] ^ dp[lca(u,v)] ^ (dp[v] ^ dp[lca(u,v)] = dp[u] ^ dp[v]。

    可以发现我们甚至都不需要计算出lca就能实现维护。

    对于非树边的打标记操作,有很多种做法,看很多大佬都用的LCT,但是本蒟蒻并不会。

    我这里用了树剖来维护。

    有很多细节需要注意:首先这里可能是很多的不同的树,所以需要不断增长下标来保证线段树的节点不会冲突.

    id,rk这些数组也同理。

    同时由于这里维护的是边的状态,那么我们可以用每个点来代表他与父节点连通的那条边的状态。

    这样也会导致我们树剖跳链的时候会把lca代表的那条边算上,但实际上是不应该算上的。

    这里我想到了两种处理方法,一种不直接跳到lca,而是最后倍增跳,第二种是我们再单独对lca进行一次处理。

    我这里用了第二种做法,但是这里又可能出现前面被标记过然后再标记的情况,所以我们就需要去维护标记次数。

    因为除了比较特殊的lca之外,其他点肯定只会被标记一次,所以我们对线段树上的叶子要做稍微不一样的处理。

    最后再有亿点细节就解决了.

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    const int N = 3e5 + 5;
    const int M = 5e5 + 5;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    
    int n,q,fa[N],ans[M];
    int ssize[N],son[N],top[N],id[N],rk[N],ffa[N],tim = 0,tot = 0,vis[N],rt[N],dep[N],dp[N],st[N],ed[N];
    struct Edge{int to,dis;};
    vector<Edge> G[N];
    int Find(int x) {return x == fa[x] ? x : fa[x] = Find(fa[x]);}
    struct PT{int u,v,x;}p[M];
    void dfs1(int u,int fa) {
        ssize[u] = 1;
        vis[u] = tot;
        ffa[u] = fa;
        dep[u] = dep[fa] + 1;
        for(auto v : G[u]) {
            if(v.to == fa) continue;
            dp[v.to] = dp[u] ^ v.dis;
            dfs1(v.to,u);
            ssize[u] += ssize[v.to];
            if(ssize[v.to] > ssize[son[u]]) son[u] = v.to;
        }
    }
    void dfs2(int u,int fa,int sta) {
        id[u] = ++tim;
        rk[tim] = u;
        top[u] = sta;
        if(son[u] == 0) return ;
        dfs2(son[u],u,sta);
        for(auto v : G[u]) {
            if(v.to == fa || v.to == son[u]) continue;
            dfs2(v.to,u,v.to);
        }
    }
    int mx;
    struct Node{int L,r,cnt,tag;}node[N << 2];
    void Pushup(int idx) {
        node[idx].cnt = node[idx << 1].cnt + node[idx << 1 | 1].cnt;
    }
    void Pushdown(int idx) {
        if(node[idx].tag != 0) {
            if(node[idx << 1].L == node[idx << 1].r) node[idx << 1].cnt++;
            else node[idx << 1].cnt = node[idx << 1].r - node[idx << 1].L + 1;
            if(node[idx << 1 | 1].L == node[idx << 1 | 1].r) node[idx << 1 | 1].cnt++;
            else node[idx << 1 | 1].cnt = node[idx << 1 | 1].r - node[idx << 1 | 1].L + 1;
            node[idx << 1].tag = node[idx << 1 | 1].tag = 1;
            node[idx].tag = 0;
        }
    }
    void build(int L,int r,int idx) {
        mx = max(mx,idx);
        node[idx].L = L,node[idx].r = r,node[idx].cnt = node[idx].tag = 0;
        if(L == r) return ;
        int mid = (L + r) >> 1;
        build(L,mid,idx << 1);
        build(mid + 1,r,idx << 1 | 1);
        Pushup(idx);
    }
    void update(int L,int r,int idx) {
        if(node[idx].L >= L && node[idx].r <= r) {
            if(node[idx].L == node[idx].r) node[idx].cnt++;
            else node[idx].cnt = node[idx].r - node[idx].L + 1;
            node[idx].tag = 1;
            return ;
        }
        Pushdown(idx);
        int mid = (node[idx].L + node[idx].r) >> 1;
        if(mid >= L) update(L,r,idx << 1);
        if(mid < r) update(L,r,idx << 1 | 1);
        Pushup(idx);
    }
    void upd(int x,int idx) {
        if(node[idx].L == node[idx].r) {
            node[idx].cnt--;
            return ;
        }
        Pushdown(idx);
        int mid = (node[idx].L + node[idx].r) >> 1;
        if(mid >= x) upd(x,idx << 1);
        else upd(x,idx << 1 | 1);
        Pushup(idx);
    }
    int query(int L,int r,int idx) {
        if(node[idx].L >= L && node[idx].r <= r) return node[idx].cnt;
        int mid = (node[idx].r + node[idx].L) >> 1,ans = 0;
        Pushdown(idx);
        if(mid >= L) ans += query(L,r,idx << 1);
        if(mid < r) ans += query(L,r,idx << 1 | 1);
        return ans;
    }
    int qy(int x,int idx) {
        if(node[idx].L == node[idx].r) return node[idx].cnt;
        int mid = (node[idx].r + node[idx].L) >> 1;
        Pushdown(idx);
        if(mid >= x) return qy(x,idx << 1);
        else return qy(x,idx << 1 | 1);
    }
    pii Tree_query(int x,int y) {
        int ans = 0;
        while(top[x] != top[y]) {
            if(dep[top[x]] < dep[top[y]]) swap(x,y);
            ans += query(id[top[x]],id[x],rt[vis[x]]);
            x = ffa[top[x]];
        }
        if(dep[x] > dep[y]) swap(x,y);
        ans += query(id[x],id[y],rt[vis[x]]);
        ans -= qy(id[x],rt[vis[x]]);
        return pii{ans,x};
    }
    void Tree_update(int x,int y) {
        while(top[x] != top[y]) {
            if(dep[top[x]] < dep[top[y]]) swap(x,y);
            update(id[top[x]],id[x],rt[vis[x]]);
            x = ffa[top[x]];
        }
        if(dep[x] > dep[y]) swap(x,y);
        update(id[x],id[y],rt[vis[x]]);
        upd(id[x],rt[vis[x]]);
    }
    int main() {
        scanf("%d %d",&n,&q);
        for(int i = 1;i <= n;++i) fa[i] = i;
        for(int i = 1;i <= q;++i) {
            scanf("%d %d %d",&p[i].u,&p[i].v,&p[i].x);
            int xx = Find(p[i].u),yy = Find(p[i].v);
            if(xx != yy) {
                fa[xx] = yy;
                ans[i] = 1;
                G[p[i].u].push_back(Edge{p[i].v,p[i].x});
                G[p[i].v].push_back(Edge{p[i].u,p[i].x});
            }
        }
        for(int i = 1;i <= n;++i) {
            if(vis[i]) continue;
            st[++tot] = tim + 1;
            dfs1(i,0);
            dfs2(i,0,i);
            ed[tot] = tim;
            rt[tot] = mx + 1;
            mx = 0;
            build(st[tot],ed[tot],rt[tot]);
        }
        for(int i = 1;i <= q;++i) {
            if(ans[i] == 1) continue;
            pii ma = Tree_query(p[i].u,p[i].v);
            if(ma.first == 0 && (dp[p[i].u] ^ dp[p[i].v] ^ p[i].x) == 1) {
                ans[i] = 1;
                Tree_update(p[i].u,p[i].v);
            }
            //printf("u is %d v is %d ma.first is %d ans[%d] is %d
    ",p[i].u,p[i].v,ma.first,i,ans[i]);
        }
        for(int i = 1;i <= q;++i) printf("%s
    ",ans[i] ? "YES" : "NO");
        system("pause");
        return 0;
    }
    View Code
  • 相关阅读:
    bzoj2957 -- 线段树
    bzoj2209 [ JSOI2011 ] -- splay
    bzoj3874 [ AHOI2014 ] -- 爬山算法
    bzoj1038 [ ZJOI2008 ] -- 模拟退火+二分
    bzoj2428 [ HAOI2006 ] -- 模拟退火
    bzoj3680 -- 模拟退火
    bzoj4500 -- 差分约束
    bzoj3527 -- FFT
    bzoj1013 [ JSOI2008 ] -- 高斯消元
    使用nginx try_files 指令 管理静态资源
  • 原文地址:https://www.cnblogs.com/zwjzwj/p/15146015.html
Copyright © 2011-2022 走看看