AtCoder Beginner Contest 212題解
前言
好久沒有打ABC了 ,上一次打已經是ABC196了,震驚這次有8題,世界第一也來了,30min就全切了,可惜我只會ABCD。
upd:我好像會E了。
Alloy
題目大意
給兩個數,要判斷這兩個數在哪個範圍,範圍就不用解釋了吧······
題解
直接if
判斷即可,非常簡單。
程式碼
#include<bits/stdc++.h> using namespace std; int main() { int a,b; cin>>a>>b; if(a==0&&b>0)puts("Silver"); if(a>0&&b==0)puts("Gold"); if(a>0&&b>0)puts("Alloy"); return 0; }
Weak Password
題目大意
給一個數字的 PIN,要判斷這個 PIN 的強弱,如果出現下面兩種情況之一,就算弱:
- 四位相同,見樣例一。
- 每相鄰兩位遞增\(1\),如\(0\)後接著\(1\),\(1\)後接著\(2\),注意\(9\)後接著\(0\),見樣例三。
題解
對於判定\(1\),直接if
判斷即。
對於判定\(2\),掃一遍數列合不合法,因為\(9\)後接著\(0\),所以要特別判定一下,當然也可以直接與\(10\)取餘。
輸入時用字串處理比較方便,注意陣列下標從\(0\)開始。
程式碼
#include<bits/stdc++.h> using namespace std; int main() { char ch[5]; bool flag; cin>>ch; if(ch[0]==ch[1]&&ch[1]==ch[2]&&ch[2]==ch[3]) { puts("Weak"); return 0; } flag=true; for(int i=0;i<=2;i++) if(ch[i+1]-'0'!=(ch[i]-'0'+1)%10) { flag=false; break; } if(flag==true)puts("Weak"); else puts("Strong"); return 0; }
Min Difference
題目大意
已知兩個數列\(A\)和\(B\),求:
\[\min|A_i-B_j|(1\le i\le n,1\le j\le m) \]題解
很明顯有\(O(nm)\)的暴力,可過不了這道題,考慮優化。
對於答案,我們只尋找差的絕對值較小的,而不用關心差的絕對值一定大的數,因此對於每個數而言,其實只用計算比自己大和自己小的離自己最近的兩個數即可。
所以我們先將兩個數列排序,再解決上面的問題。
但如何解決使兩個數差距儘可能小呢?可以使用雙指標\(i\)和\(j\)表示\(A_i\)和\(B_j\),我們要先思考:如果知道\(A_i\)和\(B_j\)的大小關係,是增加\(i\)
這要分成兩種情況(注意已經按升序排好):
- \(A_i>B_j\),這時候增加\(j\),因為增加\(i\)只會使兩個數差距越來越大。
- \(A_i\le B_j\),這時候增加\(i\),因為增加\(j\)只會使兩個數差距越來越大。
注意兩個指標會遍歷兩個數列,所以遍歷的時間複雜度為\(O(n+m)\),加上排序,總時間為\(O(n\log n+m\log m)\)。
程式碼
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+7;
int a[N],b[N];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=m;i++)scanf("%d",&b[i]);
sort(a+1,a+n+1);
sort(b+1,b+m+1);
int ans=INT_MAX;
for(int i=1,j=1;i<=n&&j<=m;)
{
ans=min(ans,abs(a[i]-b[j]));
if(a[i]>b[j]) j++;
else i++;
}
printf("%d",ans);
return 0;
}
Querying Multiset
題目大意
維護一個包?資料結構,滿足以下三種操作:
- 在一個空球上面寫一個整數\(X\),並把這個球放入包內。
- 對於包內的所有球,將每個球上面的整數加上\(X\)。
- 輸出包中所有球上的最小的數字,並把這個球扔掉.
題解
對於這種帶加入刪除的整體最大最小值問題,很明顯就是堆,對於這道題,只要維護一個小根堆。
因為操作\(2\)不可能將所有數都暴力模擬,但對於同一基準的數,不管加上多少,數的大小關係總不變,因此我們來解決如何把數都變成同一標準。
先記錄一下操作\(2\)加了多少,記為\(sum\),這樣每個數就可以表示為\(a_i+sum\)(\(a_i\)為同一基準數)。
先不考慮操作\(3\),對於每次操作\(1\),將\(X-sum\)就可以將加入的數\(X\)與堆中的其他數變成同一標準,因為這個數加入之前的操作\(2\)的值與這個數是無關的,如果還不明白,那就舉個例子:
假設現在只有一個數\(X\),進行了一次操作\(2\),所加總和記為\(sum\)。
進行了一次操作\(1\),加入了一個數\(Y-sum\)。
又進行了一次操作\(2\),加上了一個數\(k\),所加總和記為\(sum+k\)。
此時\(X\)的值為\(X+sum+k\),\(Y\)的值為\(Y-sum+sum+k=Y+k\)。
操作\(2\)很簡單,直接將\(sum+X\)就可以了。
操作\(3\)的話也很簡單,直接取隊頭的值\(a_{top}+sum\)就可以了。
注意開long long
,時間複雜度為\(O(n\log n)\)。
程式碼
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int n;
priority_queue<LL,vector<LL>,greater<LL> > heap;
LL sum;
int main()
{
scanf("%d",&n);
while(n--){
int op,x;
scanf("%d",&op);
if(op==1){
scanf("%d",&x);
heap.push(x-sum);
}
else if(op==2){
scanf("%d",&x);
sum+=x;
}
else{
printf("%lld\n",heap.top()+sum);
heap.pop();
}
}
return 0;
}