• 2014-2015 ACM-ICPC, NEERC, Southern Subregional Contest 题解(PART)(9/13)


    $$2014-2015 ACM-ICPC, NEERC, Southern Subregional Contest$$

    A Nasta Rabbara

    B Colored Blankets

    只要每组都能用两种以下的颜色合成即可,可以发现答案必然存在,考虑用数量最多的颜色和数量最少的颜色组合,递归处理
    略证:颜色最少的数量(le frac{k}{n}),颜色最多的数量(ge frac{k}{n}),每次组合完成之后上述条件不变

    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<bits/stdc++.h>
    using namespace std;
    function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
    const int MAXN = 1e3+7;
    int n,m,k,cnt[MAXN];
    pair<int,int> color[MAXN];
    vector<int> vec[MAXN];
    set<pair<int,int>> S;
    int main(){
        scanf("%d %d",&n,&k);
        m = n / k;
        for(int i = 1; i <= n; i++){
            scanf("%d",&color[i].first);
            if(color[i].first==-1) color[i].first = 1;
            vec[color[i].first].emplace_back(i);
        }
        for(int i = 1; i <= k; i++) if(!vec[i].empty()) S.insert(make_pair(vec[i].size(),i));
        puts("Yes");
        while(!S.empty()){
            auto va = *S.begin();
            auto vb = *S.rbegin();
            if(va==vb){
                int col = vb.second;
                while(!vec[col].empty()){
                    color[vec[col].back()].second = col;
                    vec[col].pop_back();
                }
                S.clear();
            }
            else{
                S.erase(va);
                S.erase(vb);
                int lft = m - va.first%m;
                int col = vb.second;
                for(int i = 0; i < lft; i++){
                    color[vec[col].back()].second = va.second;
                    vec[col].pop_back();
                }
                col = va.second;
                for(int i = 0; i < m - lft; i++){
                    color[vec[col].back()].second = vb.second;
                    vec[col].pop_back();
                }
                va.first-=m-lft;
                if(va.first) S.insert(va);
                vb.first-=lft;
                if(vb.first) S.insert(vb);
            }
        }
        for(int i = 1; i <= n; i++) printf("%d %d
    ",color[i].first,color[i].second);
        return 0;
    }
    

    C Component Tree

    D Data Center

    排序之后先选上最大的直到大于(m),然后再从剩下的里从大到小遍历,用标记为(1)的替换标记为(0)的,直到不能替换位置

    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<bits/stdc++.h>
    using namespace std;
    function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
    using LL = int_fast64_t;
    const int MAXN = 2e5+7;
    int n;
    LL m;
    struct STA{
        LL val;
        int v,idx;
        bool operator < (const STA &rhs)const{ return val > rhs.val; }
    }sta[MAXN];
    int main(){
        scanf("%d %I64d",&n,&m);
        for(int i = 1; i <= n; i++){
            sta[i].idx = i;
            scanf("%I64d %d",&sta[i].val,&sta[i].v);
        }
        sort(sta+1,sta+1+n);
        priority_queue<STA,vector<STA>> que;
        vector<int> vec;
        LL sum = 0;
        for(int i = 1; i <= n; i++){
            if(sum<m){
                sum+=sta[i].val;
                if(!sta[i].v) que.push(sta[i]);
                else vec.emplace_back(sta[i].idx);
            }
            else{
                if(que.empty()) break;
                if(!sta[i].v) continue;
                if(sum-que.top().val+sta[i].val>=m){
                    sum = sum-que.top().val+sta[i].val;
                    que.pop();
                    vec.emplace_back(sta[i].idx);
                }
            }
        }
        printf("%d %d
    ",vec.size()+que.size(),vec.size());
        for(int i = 0; i < (int)vec.size(); i++) printf("%d ",vec[i]);
        while(!que.empty()){
            printf("%d ",que.top().idx);
            que.pop();
        }
        return 0;
    }
    

    E Election of a Mayor

    设当前赢了(w)场,现在考虑合并的时候没有减少赢的场次的有(x)次,减少了1次赢的场次的有(y)次,不可能合并两次都赢的
    那么(frac{w-y}{n-x-y}>frac{1}{2} => x-y>n-2·w => x-yge n-2·w+1)
    所以尽量合并那些合并之后没有减少赢的场次的即可,dp

    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<bits/stdc++.h>
    using namespace std;
    function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
    const int MAXN = 2e5+7;
    int n,win,k,f[MAXN];
    pair<int,int> sta[MAXN];
    vector<pair<int,int>> vec;
    int main(){
        scanf("%d",&n);
        for(int i = 1; i <= n; i++){
            scanf("%d %d",&sta[i].first,&sta[i].second);
            win += sta[i].first>sta[i].second?1:0;
        }
        k = n - 2*win + 1;
        if(k<=0) return printf("%d
    ",0),0;
        for(int i = 2; i <= n; i++){
            if(sta[i].first>sta[i].second){
                if(sta[i-1].first>sta[i-1].second) f[i] = f[i-1];
                else if(sta[i-1].first==sta[i-1].second) f[i] = max(f[i-1],f[i-2]+1);
                else{
                    if(sta[i].first+sta[i-1].first<=sta[i].second+sta[i-1].second) f[i] = f[i-1];
                    else f[i] = max(f[i-1],f[i-2]+1);
                }
            }
            else if(sta[i].first==sta[i].second) f[i] = max(f[i-1],f[i-2]+1);
            else{
                if(sta[i-1].first>sta[i-1].second){
                    if(sta[i-1].first+sta[i].first>sta[i-1].second+sta[i].second) f[i] = max(f[i-1],f[i-2]+1);
                    else f[i] = f[i-1];
                }
                else f[i] = max(f[i-1],f[i-2]+1);
            }
            if(f[i]==k){
                int cur = k, pos = i;
                while(cur){
                    if(f[pos]==cur&&f[pos-1]!=cur){
                        vec.emplace_back(make_pair(pos-1,pos));
                        pos-=2;
                        cur--;
                    }
                    else pos--;
                }
                printf("%d
    ",k);
                for(int i = k-1; i >= 0; i--) printf("%d %d
    ",vec[i].first,vec[i].second);
                return 0;
            }
        }
        puts("-1");
        return 0;
    }
    

    F Ilya Muromets

    其实就是选两部分长为k的区间使和最大,简单DP

    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<bits/stdc++.h>
    using namespace std;
    function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
    const int MAXN = 2e5+7;
    int n,m,A[MAXN],sum[MAXN],f[MAXN][2];
    int main(){
        scanf("%d %d",&n,&m);
        for(int i = 1; i <= n; i++) scanf("%d",&A[i]);
        if(m*2>=n){
            printf("%d
    ",accumulate(A+1,A+n+1,0));
            return 0;
        }
        partial_sum(A+1,A+1+n,sum+1);
        for(int i = m; i <= n; i++){
            f[i][0] = max(sum[i] - sum[i-m],f[i-1][0]);
            f[i][1] = max(f[i-m][0] + sum[i] - sum[i-m],f[i-1][1]);
        }
        printf("%d
    ",f[n][1]);
        return 0;
    }
    

    G FacePalm Accounting

    从前往后遍历,尽量选择靠后位置的减小

    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<bits/stdc++.h>
    using namespace std;
    function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
    const int MAXN = 2e5+7;
    int n,k,A[MAXN],tot;
    stack<int> stk;
    struct BinaryIndexedTree{
        int val[MAXN];
        #define lowbit(x) (x)&-(x)
        void update(int pos, int x){
            while(pos<=n){
                val[pos] += x;
                pos += lowbit(pos);
            }
        }
        int query(int pos){
            int res = 0;
            while(pos){
                res += val[pos];
                pos -= lowbit(pos);
            }
            return res;
        }
    }BIT;
    int main(){
        scanf("%d %d",&n,&k);
        for(int i = 1; i <= n; i++){
            scanf("%d",&A[i]);
            BIT.update(i,A[i]);
        }
        int minn = *min_element(A+1,A+1+n);
        for(int i = 1; i < k; i++) stk.push(i);
        for(int i = k; i <= n; i++){
            stk.push(i);
            int sum = BIT.query(i) - BIT.query(i-k);
            if(sum>=0) tot+=sum+1;
            while(sum>=0){
                if(A[stk.top()]-minn>sum+1){
                    A[stk.top()] -= sum+1;
                    BIT.update(stk.top(),-sum-1);
                    sum = -1;
                }
                else{
                    BIT.update(stk.top(),minn-A[stk.top()]);
                    sum-=A[stk.top()] - minn;
                    A[stk.top()] = minn;
                    stk.pop();
                }
            }
        }
        printf("%d
    ",tot);
        for(int i = 1; i <= n; i++) printf("%d ",A[i]);
        puts("");
        return 0;
    }
    

    H Minimal Agapov Code

    I Sale in GameStore

    签到,选上最大的,剩下的0-1背包即可

    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<bits/stdc++.h>
    using namespace std;
    function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
    const int MAXN = 1e5+7;
    int n,f[MAXN];
    int main(){
        scanf("%d",&n);
        vector<int> vec(n);
        for(int i = 0; i < n; i++) scanf("%d",&vec[i]);
        sort(vec.begin(),vec.end());
        int mon = vec.back();
        vec.pop_back();
        for(int i = 0; i < (int)vec.size(); i++)
            for(int j = mon; j >= vec[i]; j--)
                f[j] = max(f[j],f[j-vec[i]]+1);
        printf("%d
    ",1+f[mon]);
        return 0;
    }
    

    J Getting Ready for VIPC

    K Treeland

    考虑离当前节点最远的点必然是叶子节点,叶子节点只有一个点离它距离为1,将叶子节点和最近点连边,然后删除叶子节点,重复操作即可

    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<bits/stdc++.h>
    using namespace std;
    function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
    const int MAXN = 2222;
    int T,n,A[MAXN][MAXN],del[MAXN];
    int main(){
        scanf("%d",&T);
        for(int kase = 1; kase <= T; kase++){
            scanf("%d",&n);
            for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) scanf("%d",&A[i][j]);
            for(int i = 1; i <= n; i++) del[i] = 0;
            vector<pair<int,int>> vec;
            for(int i = n; i >= 3; i--){
                int v = A[1][i];
                for(int j = 2; j <= n; j++){
                    if(del[A[v][j]]) continue;
                    vec.emplace_back(make_pair(v,A[v][j]));
                    del[v] = 1;
                    break;
                }
            }
            vec.emplace_back(make_pair(1,A[1][2]));
            for(auto p : vec) printf("%d %d
    ",p.first,p.second);
            puts("");
        }
        return 0;
    }
    

    L Useful Roads

    (1)为根建立支配树,遍历每条边,如果是支配树上的返祖边,那必然会经过祖先两次,即不是useful road

    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<bits/stdc++.h>
    using namespace std;
    function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
    const int MAXN = 2e5+7;
    int n,m,dfn[MAXN],idx[MAXN],num,degree[MAXN],depth[MAXN],par[MAXN][20],root[MAXN],semi[MAXN],msemi[MAXN];
    pair<int,int> edge[MAXN];
    vector<int> G[MAXN],from[MAXN],rG[MAXN],rfrom[MAXN],newG[MAXN],node;
    void init(){
        for(int i = 1; i <= n; i++){
            G[i].clear();
            from[i].clear();
            rG[i].clear();
            rfrom[i].clear();
            newG[i].clear();
            memset(par[i],0,sizeof(par[i]));
            dfn[i] = idx[i] = degree[i] = 0;
        }
        num = 0;
        node.clear();
    }
    void tarjan(int u){
        dfn[u] = ++num;
        idx[num] = u;
        for(int v : G[u]){
            if(dfn[v]) continue;
            tarjan(v);
            rG[u].emplace_back(v);
            rfrom[v].emplace_back(u);
            degree[v]++;
        }
    }
    int findroot(int u){
        if(u!=root[u]){
            int rt = root[u];
            root[u] = findroot(root[u]);
            msemi[u] = min(msemi[u],msemi[rt]);
        }
        return root[u];
    }
    void calsemi(){
        for(int i = 1; i <= n; i++){
            root[i] = i;
            msemi[i] = dfn[i];
        }
        for(int i = n; i >= 2; i--){
            if(!idx[i]) continue;
            int u = idx[i],tar = n;
            for(int v : from[u]){
                if(!dfn[v]) continue;
                if(dfn[v]<dfn[u]) tar = min(tar,dfn[v]);
                else{
                    findroot(v);
                    tar = min(tar,msemi[v]);
                }
            }
            semi[u] = idx[tar];
            msemi[u] = tar;
            root[u] = rfrom[u][0];
            rG[semi[u]].emplace_back(u);
            rfrom[u].emplace_back(semi[u]);
            degree[u]++;
        }
    }
    void toposort(){
        queue<int> que;
        que.push(1);
        while(!que.empty()){
            int u = que.front();
            que.pop();
            for(int v : rG[u]){
                degree[v]--;
                if(!degree[v]){
                    node.emplace_back(v);
                    que.push(v);
                }
            }
        }
    }
    int LCA(int u, int v){
        if(depth[u]<depth[v]) swap(u,v);
        for(int i = 0; i < 20; i++) if((depth[u]-depth[v])&(1<<i)) u = par[u][i];
        if(u==v) return u;
        for(int i = 19; i >= 0; i--) if(par[u][i]!=par[v][i]){
            u = par[u][i];
            v = par[v][i];
        }
        return par[u][0];
    }
    void buildtree(){
        for(int u : node){
            if(rfrom[u].empty()) continue;
            par[u][0] = rfrom[u][0];
            for(int v : rfrom[u]) par[u][0] = LCA(par[u][0],v);
            depth[u] = depth[par[u][0]] + 1;
            newG[par[u][0]].emplace_back(u);
            for(int i = 1; par[u][i-1]; i++) par[u][i] = par[par[u][i-1]][i-1];
        }
    }
    int main(){
        while(scanf("%d %d",&n,&m)!=EOF){
            init();
            for(int i = 1; i <= m; i++){
                scanf("%d %d",&edge[i].first,&edge[i].second);
                from[edge[i].second].emplace_back(edge[i].first);
                G[edge[i].first].emplace_back(edge[i].second);
            }
            tarjan(1);
            calsemi();
            toposort();
            buildtree();
            vector<int> vec;
            for(int i = 1; i <= m; i++){
                if(!dfn[edge[i].first]||!dfn[edge[i].second]) continue;
                int lca = LCA(edge[i].first,edge[i].second);
                if(lca!=edge[i].second) vec.emplace_back(i);
            }
            printf("%d
    ",vec.size());
            for(int x : vec) printf("%d ",x);
            puts("");
        }
        return 0;
    }
    

    M Variable Shadowing

    用栈模拟即可

    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<bits/stdc++.h>
    using namespace std;
    function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
    const int MAXN = 111;
    int n,tot;
    char prog[MAXN][MAXN];
    stack<int> bracket;
    stack<pair<int,pair<int,int>>> alp[MAXN];
    vector<pair<pair<pair<int,int>,pair<int,int>>,char>> res;
    int main(){
        ____();
        cin >> n;
        cin.get();
        for(int i = 1; i <= n; i++) cin.getline(prog[i]+1,MAXN);
        bracket.push(0);
        for(int i = 1; i <= n; i++){
            int len = strlen(prog[i]+1);
            for(int p = 1; p <= len; p++){
                if(prog[i][p]==' ') continue;
                if(prog[i][p]=='{') bracket.push(++tot);
                else if(prog[i][p]=='}'){
                    for(int k = 0; k < 26; k++) while(!alp[k].empty()&&alp[k].top().first==bracket.top()) alp[k].pop();
                    bracket.pop();
                }
                else{
                    int ch = prog[i][p] - 'a';
                    if(!alp[ch].empty()) res.emplace_back(make_pair(make_pair(make_pair(i,p),alp[ch].top().second),prog[i][p]));
                    alp[ch].push(make_pair(bracket.top(),make_pair(i,p)));
                }
            }
        }
        for(auto p : res){
            cout << p.first.first.first << ':' << p.first.first.second << ": warning: shadowed declaration of " << p.second
            << ", the shadowed position is " << p.first.second.first << ':' << p.first.second.second << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    单例/单体模式(Singleton)
    步步为营 .NET 设计模式学习笔记 六、Adapter(适配器模式)
    分享18个非常棒的 jQuery 表格插件
    线程池 vs 专有线程
    介绍27款经典的CSS框架
    一些系统开发及项目管理的资料
    SQL数据库中的XML应用
    SQLite之初体验
    AsyncBox 一款基于 jQuery 的弹窗组件
    弹出图片层
  • 原文地址:https://www.cnblogs.com/kikokiko/p/12203781.html
Copyright © 2020-2023  润新知