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;
}
原文地址:https://www.cnblogs.com/kikokiko/p/12203781.html