2020 智算之道 初赛 第三场

2020 中国软件行业智能应用程序设计大赛
(奇怪的比赛……似乎算是IOI赛制,最高分最短运行时间排名靠前,题目有部分分)

第一题

2020 智算之道 初赛 第三场_第1张图片

解答

维护当前温度和当前体积,按要求修改或输出信息

官方题解

在这里插入图片描述

#include
#include
#include
#include
using namespace std;
const int N = 2020;
int n,l,a,b;
inline int read(){
    int x=0, f=1;
    char t=getchar();
    while(t>'9'||t<'0'){if(t=='-')f=-1;t=getchar();}
    while(t>='0'&&t<='9')x=x*10+t-'0',t=getchar();
    return x*f;
}
int main(){
    n = read();
    l = read();
    a=read();
    b=read();
    int opt;
    int wendu = 0;
    int tiji = 0;
    for(int i=1;i<=n;i++){
        opt=read();
        if(opt==3){
            if(wendu>=a && wendu<=b && tiji>=l) printf("%d\n", wendu);
            else puts("GG");
        }else{
            if(opt==1){
                wendu=read();
            }else{
                tiji = read();
            }
        }
    }
    return 0;
}

第二题

2020 智算之道 初赛 第三场_第2张图片

解答

在整个过程中,维护同一人手牌中同一点数的牌最多只有一张。
维护双向链表表示两人的手牌,简单起见设置首尾为“哨兵节点”。维护map<点数,指针>快速查找牌的位置。
整个过程中,每次摸牌,若已有此点数的牌,从双向链表和map中删去之前的牌;若没有,加入作为最后一张手牌。
为什么题设游戏一定在有限次数内结束是对的:
从牌堆摸牌结束时,(n-2)种4张同点数的牌必然要么两人各剩一张,要么两人各剩0张;2种3张同点数的牌必然一人1张,另一人0张。
互相抽牌过程中,抽对方的第一张牌成为自己的最后一张牌,双方的牌仿佛连成一圈,转一圈过程中每张牌必然被抽到。(n-2)种两人各剩一张,一旦其中一张被抽到,即成为两人各剩0张。最终2种,即使一人一张,下一次抽游戏结束。

官方题解

2020 智算之道 初赛 第三场_第3张图片

#include
#include
#include
#include
using namespace std;

inline int read(){
    int x=0, f=1;
    char t=getchar();
    while(t>'9'||t<'0'){if(t=='-')f=-1;t=getchar();}
    while(t>='0'&&t<='9')x=x*10+t-'0',t=getchar();
    return x*f;
}
#include
#include
struct Node{
    int val;
    Node *lst, *nxt;
}*head[2], *tail[2];
map<int,Node*> mp[2];
int main(){
    int n = read();
    head[0] = new Node;
    tail[0] = new Node;
    head[1] = new Node;
    tail[1] = new Node;
    head[0]->nxt = tail[0];
    tail[0]->lst = head[0];
    head[1]->nxt = tail[1];
    tail[1]->lst = head[1];
    int a;
    for(int i=1;i<=4*n-2;i++){
        int id = i&1^1;
        int x = read();
        if(mp[id].count(x)){
            mp[id][x]->nxt->lst = mp[id][x]->lst;
            mp[id][x]->lst->nxt = mp[id][x]->nxt;
            Node *ptr = mp[id][x];
            mp[id].erase(x);
            delete ptr;
        }else{
            Node *ptr = new Node;
            ptr->val = x;
            ptr->lst = tail[id]->lst;
            ptr->nxt = tail[id];
            ptr->lst->nxt = ptr;
            ptr->nxt->lst = ptr;
            mp[id][x] = ptr;
        }
    }
    int cnt = 0;
    for(int id=0;head[0]->nxt!=tail[0] && head[1]->nxt!=tail[1];id^=1){
        ++cnt;
        Node *ptr = head[id^1]->nxt;
        head[id^1]->nxt = ptr->nxt;
        head[id^1]->nxt->lst = head[id^1];
        int x = ptr->val;
        mp[id^1].erase(x);
        if(mp[id].count(x)){
            mp[id][x]->nxt->lst = mp[id][x]->lst;
            mp[id][x]->lst->nxt = mp[id][x]->nxt;
            Node *ptr = mp[id][x];
            mp[id].erase(x);
            delete ptr;
        }else{
            Node *ptr = new Node;
            ptr->val = x;
            ptr->lst = tail[id]->lst;
            ptr->nxt = tail[id];
            ptr->lst->nxt = ptr;
            ptr->nxt->lst = ptr;
            mp[id][x] = ptr;
        }
    }
    printf("%d\n",cnt);
    return 0;
}

第三题

2020 智算之道 初赛 第三场_第4张图片

解答

随便举几个例子可以发现,根深度相同的子树如果在排列中互相纠缠,会造成代价无谓的增加(一棵树根远离所有子节点,一棵树部分子节点远离根)。
后出现的子树树根,相当于在代价计算中“越过”先出现的子树节点,后被“越过”的子树依次比先被“越过”的子树,节点数计入总代价少算一次。由排列不等式(人教版 高三数学选修4-5)反序和≤乱序和≤顺序和,节点数少的子树排在前面。

官方题解

2020 智算之道 初赛 第三场_第5张图片

#include
#include
#include
#include
using namespace std;

inline int read(){
    int x=0;
    char t=getchar();
    while(t>'9'||t<'0')t=getchar();
    while(t>='0'&&t<='9')x=x*10+t-'0',t=getchar();
    return x;
}
const int N = 600000+100;
int n,k;
#include
vector<int>e[N];
int sz[N];

bool cmp(const int x,const int y){
    return sz[x] < sz[y];
}
void dfs(int u){
    sz[u] = 1;
    for(int i=0;i<e[u].size();i++){
        int v=e[u][i];
        dfs(v);
        sz[u] += sz[v];
    }
    sort(e[u].begin(),e[u].end(), cmp);
}
int main(){
    n = read();
    k=read();
    for(int v=2,u;v<=n;v++){
        u=read();
        e[u].push_back(v);
    }
    dfs(1);
    typedef long long LL;
    LL ans = 0;
    for(int u=1;u<=n;u++){
        LL sum = 1;
        for(int i=0;i<e[u].size();i++){
            int v=e[u][i];
            ans += sum;
            sum += sz[v];
        }
        //printf("%lld %lld\n",sum, ans);
    }
    printf("%lld\n", (ans+1)*k);
    return 0;
}

你可能感兴趣的:(ACM)