2021-2022 ACM-ICPC Brazil Subregional Programming Contest
今天這場不是很自閉,嗯。順便試試程式碼摺疊功能。
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> 2View Codeusing 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 intmid=(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; }View Code
場上寫出來的就這些啦,後面補題再加。