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

文章目录

  • 水杯
  • 顺序安排

水杯

题目大意
D D D 有一个能显示温度的杯子. 其原理是杯盖上的一个传感器. 只有在杯子内的水的体积大于等于某个数 L L L 的时候传感器才能显示水温,并且如果水温不在 [ A , B ] [A,B] [A,B] 内传感器也无法显示水温.
注意,这里温度对水的体积没有影响
初始水杯为空,有 n n n 次操作,操作分为三种:
1 x x x 表示把水温变成 x x x.
2 x x x 表示把水的体积变成 x x x.
3 查询传感器的显示情况. 如果不能显示水温输出 G G GG GG,否则输出水温.
输入格式
第一行四个整数 n , L , A , B n,L,A,B n,L,A,B 含义如题目所示.
接下来 n n n 行,每行一个整数 o p t opt opt 或两个整数 o p t opt opt, x x x,表示执行操作 o p t opt opt
输出格式
对于所有操作 3 输出结果,每行一个答案.
数据规模与约定

对于 100 100 100 % 的数据,1 ≤ \leq n ≤ \leq 1000,-273 ≤ \leq A ≤ \leq B ≤ \leq 100,1 ≤ \leq L ≤ \leq 1000,1 ≤ \leq opt ≤ \leq 3
对于操作 1,-273 ≤ \leq x ≤ \leq 100;对于操作 2,1 ≤ \leq x ≤ \leq 1000.
样例输入

5 2 1 3
1 5
2 3
3
1 2
3

样例输出

GG
2
#include 
using namespace std;
int n,L,A,B,t,v;
int main()
{
    cin>>n>>L>>A>>B;
    while(n--)
    {
        int op,x;
        cin>>op;
        if(op==1){
            cin>>x;
            t=x;
        }
        else if(op==2){
            cin>>x;
            v=x;
        }
        else{
            if(v>=L && t>=A && t<=B)
                cout<<t<<'\n';
            else cout<<"GG"<<'\n';
        }
    }
    return 0;
}

题目大意
A l i c e Alice Alice B o b Bob Bob 在打扑克.
有一副点数为 1 ⋯ \cdots n n n 的扑克牌,除了两种点数只有三张牌以外,其余的点数都有四张牌,点数相同的牌认为是相同的. 给出一个牌的顺序, A l i c e Alice Alice B o b Bob Bob 轮流按顺序摸牌, A l i c e Alice Alice 先手,当某个人新摸到的牌已经在 T a Ta Ta 的手牌中存在时,把这两张牌同时从 T a Ta Ta 的手牌中移除. 注意手牌的顺序是摸牌的顺序.
摸完牌后,从 A l i c e Alice Alice 开始,重复以下过程:
如果有人没有手牌了,那么没有手牌的人获胜,结束.
计数器 c n t cnt cnt 加一
把对方的第一张手牌放到自己的手牌中,使其成为自己的最后一张手牌. 如果该牌之前已在自己的手牌中出现过,那么把这两张牌同时从自己的手牌中移除.
由对方继续操作.
给出牌的顺序,求出 c n t cnt cnt 的值. 可以证明在有限步内游戏一定会结束.
输入格式
第一行一个整数 n n n ,表示点数为 1 ⋯ \cdots n.
第二行 4 n − 2 4n-2 4n2 个正整数,表示牌的顺序. 保证恰好有两种点数出现了三次,其余点数出现四次.
输出格式
一行一个整数表示 c n t cnt cnt 的值.
数据规模与约定
对于 50 50% 50 的数据,3 ≤ \leq n ≤ \leq 100。
对于 100 % 100\% 100% 的数据,3 ≤ \leq n ≤ \leq 100000。
样例输入

5
1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 5 5 5

样例输出

1

2020智算之道初赛第三场题解合集_第1张图片
2020智算之道初赛第三场题解合集_第2张图片

#include 
using namespace std;
const int maxn=1e5+7;
int a[maxn<<1],ap[maxn<<1],b[maxn<<1],bp[maxn<<1];
int n,cnt,topa,topb,idxa,idxb,na,nb;
void adda(int x)
{   //a[] 表示栈中存在的牌  ap[]表示出现过的牌,存的是 a[] 的下标
    if(ap[x]){
        a[ap[x]]=0;
        ap[x]=0;  
        --na;
    }
    else{
        a[++idxa]=x; 
        ap[x]=idxa;
        ++na;
    }
}
void addb(int x)
{
    if(bp[x]){
        b[bp[x]]=0;
        bp[x]=0;
        --nb;
    }
    else{
        b[++idxb]=x;
        bp[x]=idxb;
        ++nb;
    }
}
int main()
{
    ios::sync_with_stdio(false),cin.tie(0);
    cin>>n;
    for(int i=1;i<=n*4-2;++i)
    {
        int p;
        cin>>p;
        if(i&1) adda(p);
        else addb(p);
    }
    ++topa; ++topb;  //栈顶指针
    while(na && nb)
    {
        cnt++;
        if(cnt&1){
            while(!b[topb]) ++topb;  //取栈中存在的牌
            adda(b[topb]);   //从栈 b 中得到 1张牌
             addb(b[topb]);  //去除这张牌
        }
        else{
            while(!a[topa]) ++topa;
            addb(a[topa]);
            adda(a[topa]);
        }
    }
    cout<<cnt<<'\n';
    return 0;
}

顺序安排

题目大意
给定一棵有根树,对于给定的树求出对应的一种排列使得代价和最小。
对于一种排列计算代价方式如下
给定常数 k k k
a a a 的父亲在序列中的位置是 x x x a a a 在序列中的位置是 y y y
a a a 的儿子节点必须在 a a a 之后出现。
a a a 的父亲在 a a a 之前出现,代价是 k × \times × ( y − x ) (y-x) (yx)
特殊的,容易看出,树根只能放在 1 1 1 号位,则代价是 k k k
只需要输出最小代价和即可。
输入格式
第一行两个正整数 n n n k k k
接下来一行 n − 1 n - 1 n1 个正整数,代表 2 ∼ \sim n n n 每个节点的父节点编号。
输出格式
一行,输出最小代价和。
数据规模与约定
对于 10 % 10\% 10% 的数据,2 ≤ \leq n ≤ \leq 10。
对于另外 40 % 40\% 40% 的数据,保证是一条链。
对于 100 % 100\% 100% 的数据,2 ≤ \leq n ≤ \leq 600000, 1 ≤ \leq k ≤ \leq 2 × \times × 1 0 6 10^6 106
样例输入

5 2
1 1 3 3

样例输出

14

2020智算之道初赛第三场题解合集_第3张图片

#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;
int cnt[maxn];
vector<int> v[maxn], p;
bool cmp(int a, int b) { return cnt[a] < cnt[b]; }
void dfs(int u) // 求子树结点的个数
{
    cnt[u] = 1;
    int t = v[u].size();
    for (int i = 0; i < t; i++)
    {
        int e = v[u][i];
        dfs(e);
        cnt[u] += cnt[e];
    }
}
int main()
{
#ifdef LZH_LOCAL
    freopen("in.in", "r", stdin);
    // freopen("out.out", "w", stdout);
#endif
    int n, m;
    cin>>n>>m;
    for (int i = 2; i <= n; i++)
    {
        int x;
        cin>>x;
        v[x].push_back(i);
    }
    dfs(1);     //求出每棵子树结点的个数 cnt[]
    ll ans = 1; //根节点1的贡献点是1
    // 分别对 每个结点作为根节点时 计算它的子节点的贡献值
    for (int i = 1; i <= n; i++)
    {
        p.clear();
        int t = v[i].size();
        for (int j = 0; j < t; j++)
            p.push_back(v[i][j]);
        // 把结点i的所有儿子结点按照子树结点个数从小到大排序
        sort(p.begin(), p.end(), cmp);
        ll temp = 1;
        // 计算结点i的子节点到i的贡献点
        t = p.size();
        for (int j = 0; j < t; j++)
        {
            int x = p[j];
            ans += temp;
            temp += cnt[x];
        }
    }
    cout<<(ll)ans*m<<'\n';
    return 0;
}

第三题代码参考这篇题解: 题解
如果能回到两年前,再也不会选择读计算机了,我会舍弃30分选个500分左右的专科读(至于为什么说是专科,即使现在是二本,高考前老肖就说了所谓的一本和二本招人的那代人根本不认),主要是氛围不好,学习真的太累,想学其余的东西还得自己花钱去学,我现在真的累,找不到知心朋友。现在对恋爱感到厌恶,想自己一个人静静,一个人学会自律,减肥,不想考研(主要考不上电子科技大学,英语六级就甩我一条街,双非学校,我有自知)。我不知道学校的数据结构讲的什么,没有意义,今天看了yxc老师进阶课的图论,我感觉到了难,算法这种事情,除了靠努力,天赋还很重要。

你可能感兴趣的:(比赛)