2021-2022 ACM-ICPC Brazil Subregional Programming Contest

Posted on 2021-11-14 20:38  Capterlliar  阅读(363)  评论(0编辑  收藏  举报

今天这场不是很自闭,嗯。顺便试试代码折叠功能。

传送门

H - Handling the Blocks

签到题。

题意:给出1-n的排列和每个数字的颜色,颜色相同的数字可以交换位置,问最后能否形成上升序列。

解:相同颜色从小到大排,再按原来颜色的排序放进去,检查是否上升即可。

K - Kathmandu

签到题++。队友签的。

题意:给出一些时刻,询问这些时刻之间是否有大于等于T的距离。

E - Escalator

模拟题。神仙队友txy写的,一发AC。我看到这种分类讨论是真的头痛,快说,谢谢队友。

题意:有一个电梯,每次同时只能向一边运行,但可以载无数个人。从左到右运行一次要用十分钟,只要电梯上有人,就会持续运行,后到达且要去的方向不同的人只能等着。给出每个人到达的时刻和要去的方向,求电梯停下的时刻。

解:设置当前运行完成时刻和等待时刻。对于每一个到来的人,如果要去的方向与当前相同,时刻大于当前时刻且反方向有人等,方向改变;否则运行方向不变。在当前基础上加十分钟。反之亦然。

N - No Luck

暴力数据结构。

题意:给出每年I(国际)C(汽车)P(喷涂)C(大赛)发的牌子数,每位队员参加哪届比赛、获得名次和持续关注后面比赛场数。如果队员当届未获奖,但在关注的后续比赛中以该名词可以获奖,他会感到遗憾。询问每位队员会感到遗憾多少次。

解:翻译一下就是给出一个序列,q个询问,询问[a+1,a+f]区间内有几个大于等于p的值。主席树即可。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define maxx 300005
 5 int y,n;
 6 struct node{
 7     int l,r,val;
 8 }tr[maxx*40];
 9 int top=0;
10 int root[maxx]={0},a[maxx]={0},b[maxx]={0};
11 int build(int node,int l,int r){
12     node=++top;
13     if(l==r){
14         return node;
15     }
16     int mid=(l+r)/2;
17     tr[node].l=build(tr[node].l,l,mid);
18     tr[node].r=build(tr[node].r,mid+1,r);
19     return node;
20 }
21 int upd(int l,int r,int node,int x){
22     int cur=++top;
23     tr[cur]=tr[node];
24     tr[cur].val++;
25     if(l==r){
26         return cur;
27     }
28     int mid=(l+r)/2;
29     if(x>mid)
30         tr[cur].r=upd(mid+1,r,tr[node].r,x);
31     else
32         tr[cur].l=upd(l,mid,tr[node].l,x);
33     return cur;
34 }
35 int query(int l,int r,int x,int lr,int rr){
36     if(l==r)
37         return tr[rr].val-tr[lr].val;
38     int sum=0;
39     int mid=(l+r)/2;
40     if(x<=mid)
41         sum=query(l,mid,x,tr[lr].l,tr[rr].l)+tr[tr[rr].r].val-tr[tr[lr].r].val;
42     else
43         sum=query(mid+1,r,x,tr[lr].r,tr[rr].r);
44     return sum;
45 }
46 signed main(){
47     scanf("%d%d",&y,&n);
48     for(int i=1;i<=y;i++) {
49         scanf("%d", &a[i]);
50         b[i]=a[i];
51     }
52     sort(b+1,b+y+1);
53     root[0]=build(0,1,maxx);
54     for(int i=1;i<=y;i++)
55         root[i]=upd(1,maxx,root[i-1],a[i]);
56     for(int i=1;i<=n;i++){
57         int aa,p,f;
58         scanf("%d%d%d",&aa,&p,&f);
59         if(p<=a[aa]||p>b[y]){
60             printf("0\n");
61             continue;
62         }
63         int ans=query(1,maxx,p,root[aa],root[aa+f]);
64         printf("%d\n",ans);
65     }
66     return 0;
67 }
View Code

 

  然后开始了漫长的自闭。我从一点开始饿,三点饿到顶峰,中间试图写K未果,WA了好几次,看机房里什么都想吃,草稿纸也很好吃的样子(?)

  中间给txy口胡了一个E题取模凑数字做法,txy突然灵光一现,开始写,写到一半卡住了问我满足A*B-y等于B+1倍数的最大A是多少。我掏出草稿纸胡搞一通推出个式子,中间不知道哪里触发对方灵感了txy继续写,最后搞出一串看起来很优美的代码。

  然后WA了。

  期间我试图改K题改了三发错了三发,最后怀疑自己读了假题(确实)放弃挣扎,开始一起看C,始终不知道哪里不对。最后十分钟想再交一发吧,然后A了???我们?????直接下班好吧。

  刚才又看了一遍代码,要求改成最小的M,所以从高位开始试着改,循环倒着写就对了。正解好像是用扩欧做,但我俩牛头不对马嘴交流下能搞出一个AC也是蛮神奇的。

 

C - Creating Multiples

题意:给出B进制下每一位大小,从中选一位将其改小,使得新数M模(B+1)余零。输出改哪一位以及改成几,如果有多种改法,选择使得M最小的一种。

解:我一开始的想法是先拿原数模(B+1)求余数,然后再找哪一位的倍数和原数模(B+1)同余减掉。当时没有这么准确,就说取模然后瞎凑凑。然后txy发现了一件好玩的事情:对于任意的x,x^n%(x+1)的值只可能是1或x本身。当n为奇数时余1,n为偶数时余x。数学归纳法就能证。因此在凑数字的时候也将位数按奇偶分类,设余数为yu,对于奇数将其减yu,偶数减b+1-yu。因为奇数模(B+1)余1,yu个这样的数加在一起就能消掉余数,不存在小于a[i]-yu的数成立,因为a[i]小于B。偶数同理。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;

int a[200010];

int main()
{
    int b, l;
    scanf("%d%d", &b, &l);
    int yu = 0;
    for (int i = l; i >=1; i--) {
        scanf("%d", &a[i]);
        if (i % 2 == 1) {
            yu = (yu + a[i]) % (b + 1);
        }
        else {
            yu = (yu + a[i]*b) % (b + 1);
        }
    }

    if (yu == 0) {
        printf("0 0");
    }
    else {
        for (int i = l; i >= 1; i--) {
            if (i % 2 == 1) {
                if (a[i] < yu) {
                    continue;
                }
                printf("%d %d", l-i+1, a[i] - yu);
                return 0;
            }
            else {
                if (a[i] < b+1-yu) {
                    continue;
                }
                printf("%d %d", l-i+1,a[i]-b-1+yu);
                return 0;
            }
        }
        printf("-1 -1");
    }
    return 0;
}
View Code

场上写出来的就这些啦,后面补题再加。

 M. Monarchy in Vertigo

题意:一个皇位继承。具体来说就是整一个dfs序每次输出靠前的。这是什么英语阅读理解大赛啊(悲

但还是对dfs序不熟吧。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define maxx 300005
int q;
vector<int> g[maxx];
vector<int> d;
int cnt=1,num=1;
int dfn[maxx]={0};
int vis[maxx]={0};
void dfs1(int now,int fa){
    dfn[num++]=now;
    for(int i=0;i<g[now].size();i++){
        int to=g[now][i];
        if(to!=fa){
            dfs1(to,now);
        }
    }
}
signed main(){
    scanf("%d",&q);
    for(int i=1;i<=q;i++){
        int opt,x;
        scanf("%d%d",&opt,&x);
        if(opt==1)
            g[x].push_back(cnt+1),cnt++;
        if(opt==2)
            d.push_back(x);
    }
    dfs1(1,0);
    queue<int> que;
    for(int i=1;i<=q;i++)
        que.push(dfn[i]);
    for(auto i:d){
        vis[i]=1;
        while(vis[que.front()])
            que.pop();
        printf("%d\n",que.front());
    }
    return 0;
}
View Code

 G. Getting in Shape

题意:有A和B两种锻炼方式,如果做了A,可以跳过下一组练习,也可以不跳;如果做了B,那必须做下一组练习。这样会有多种不同的选择方式,现给出总选择方式N,构造字典序最小的一种锻炼方式。

解:做了B练习必须做下一组练习,因此一个B左右两侧方案数乘积是总方案。现在单考虑A,写几项发现A的数目形成的总方案是斐波那契数列。

证明:假设所有方案都是A。选到第i个,它可以由前一组做了转移而来,也可以由前一个没做转换来。但如果前一个没做,i-2一定做了。因此dp[i]=dp[i-1]+dp[i-2]。(这不就爬楼梯

因此考虑将N分解为斐波那契数的乘积,如果无法分成,则无解。然后我干了一件憨中憨的事情:按分解质因数方法分解是斐波那契数的因数,从大到小分,还在想怎么又又又WA了呢。一个数分解质因数的方案只有一种,但斐波那契数不全是质数,还是dfs吧。

代码:

#include<bits/stdc++.h>
using  namespace std;
#define ll long long
#define maxx 1005
#define int long long
int fib[105]={0};
int n;
int ans[105]={0};
int ok=0;
void solve(int now,int cnt,int num){
    if(now==1){
        ok=1;
        for(int i=1;i<cnt;i++){
            for(int j=0;j<ans[i];j++)
                printf("A");
            printf("B");
        }
        return;
    }
    for(int i=num;i>2;i--){
        if(ok)
            return;
        if(now%fib[i]==0){
            ans[cnt]=i-2;
            solve(now/fib[i],cnt+1,i);
        }
    }
}
signed main() {
    fib[1]=fib[2]=1;
    for(int i=3;i<=75;i++)
        fib[i]=fib[i-1]+fib[i-2];
    scanf("%lld",&n);
    solve(n,1,75);
    if(!ok)
        printf("IMPOSSIBLE\n");
    return 0;
}
View Code