2021-2022 ACM-ICPC Brazil Subregional Programming Contest
Posted on 2021-11-14 20:38 Capterlliar 阅读(365) 评论(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 }
然后开始了漫长的自闭。我从一点开始饿,三点饿到顶峰,中间试图写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; }
场上写出来的就这些啦,后面补题再加。
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; }
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; }