2020智算之道初赛第三场题解

A.水杯

一个模拟的水题..

Code:

int main()
{
    ll water_templat = -1,water_val = -1;
    ll L,A,B;
    read(n);read(L);read(A);read(B);
    for(int i=1;i<=n;i++){
        int opt,x;scanf("%d",&opt);
        if(opt!=3) scanf("%d",&x);
        if(opt == 1)
            water_templat = x;
        else if(opt == 2)
            water_val = x;
        else{
            if(water_templat>=A&&water_templat<=B&&water_val>=L) printf("%lld\n",water_templat);
            else printf("GG\n");
        }
    }
    return 0;
}

B.鳖

这个B...卡的直接醉了

按照题意模拟即可

模拟建议使用双端队列deque(最好还是数组吧,deque必须全局才可以)

被deque全局卡了一个小时40分钟

第一个坑点是注意摸牌顺序(可能会wa)

第二个坑点是处理摸牌顺序 (可能会T)

第三个坑点是删牌标记即可不要暴力删除(可能会T)

update:由于比赛代码通过后 博主忘记这是90分还是100分的代码了 带来不好的体验 见谅 现在已经更新正确代码

思路是一致的

代码是博主一个学长的:

Code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+7;
int A[maxn],B[maxn];
int qA[maxn<<5],qB[maxn<<5];
int lA,lB,rA,rB;
int cntA,cntB,cnt;
int ans,n;
pair<int,int> Tmp[maxn];
int main(){
    scanf("%d",&n);
    for(int i=0,x;i<4*n-2;i++){
        scanf("%d",&x);
        if(i&1){
            if(A[x]){
                cntA--;
                A[x] = 0;
            }else{
                A[x] = i+1;
                cntA++;
            }
        }else{
            if(B[x]){
                cntB--;
                B[x] = 0;
            }else{
                B[x] = i+1;
                cntB++;
            }
        }
    }
    int tot = 0;
    for(int i=1;i<=n;i++){
        if(A[i]){
            Tmp[++tot] = make_pair(A[i],i);
        }
    }
    sort(Tmp+1,Tmp+1+tot);
    for(int i=0;i<tot;i++){
        qA[i] = Tmp[i-1].second;
    }
    rA = tot-1;
    tot = 0;
    for(int i=1;i<=n;i++){
        if(B[i]){
            Tmp[++tot] = make_pair(B[i],i);
        }
    }
    sort(Tmp+1,Tmp+1+tot);
    for(int i=0;i<tot;i++){
        qB[i] = Tmp[i].second;
    }
    rB = tot-1;
    while(cntA&&cntB){
        cnt++;
        if(cnt&1){
            while(!A[qA[lA]]&&lA<=rA){
                lA++;
            }
            --cntA;
            A[qA[lA]] = 0;
            if(B[qA[lA]]){
                --cntB;
                B[qA[lA]] = 0;
            }else{
                ++cntB;
                B[qA[lA]] = 1;
                qB[++rB] = qA[lA];
                lA++;
            }
        }else{
            while(!B[qB[lB]]&&lB<=rB){
                lB++;
            }
            --cntB;
            B[qB[lB]] = 0;
            if(A[qB[lB]]){
                --cntA;
                A[qB[lB]] = 0;
            }else{
                ++cntA;
                A[qB[lB]] = 1;
                qA[++rA] = qB[lB];
                lB++;
            }
        }
        //printf("%d %d\n",cntA,cntB);
    }
    printf("%d\n",cnt);
    return 0;
}

C.顺序安排

考虑每个节点访问其儿子节点数,在访问第二个儿子时肯定要访问第一个儿子

所以说,第一个儿子的所有节点在第二个儿子节点之前

其实这就是哈夫曼树的原理了,由于k是一样的,所以遍历儿子节点时,每个儿子节点应该按照节点顺序从小到大排列

这样可以保证最大的贡献只利用了一次

Code:

int sz[maxn];
vector<int>v[maxn],g;
void dfs(int u){
    sz[u] = 1;
    int szt = v[u].size();
    for(int k=0;k<szt;k++){
        int e = v[u][k];
        dfs(e);
        sz[u] +=sz[e];
    }
}
int cmp(int a,int b){
    return sz[a] < sz[b];
}
int main()
{
    read(n);read(m);
    for(int i=2;i<=n;i++){
        int x;scanf("%d",&x);
        v[x].push_back(i);
    }
    dfs(1);
    ll ans = m;
    for(int i=1;i<=n;i++){
        g.clear();
        int szt = v[i].size();
        for(int k=0;k<szt;k++){
            int e = v[i][k];
            g.push_back(e);
        }
        sort(g.begin(),g.end(),cmp);
        ll temp = 1;
        szt = g.size();
        for(int k=0;k<szt;k++){
            int x = g[k];
            ans += temp*m;
            temp += sz[x];
        }
    }
    printf("%lld\n",ans);
    return 0;
}

总结:

这次被B卡了1个小时40分钟,以至于A和C都没时间优化,C本来想着后期用链式前向星之类+并查集优化一下的

以后队列这种太大还是数组模拟吧..

最后rk3唉。

最后...这是打过最假的一场

猜你喜欢

转载自blog.csdn.net/qq_43857314/article/details/107599580