Codeforces Round #631 (Div. 2)
A. Dreamoon and Ranking Collection
題意:
已知過去 $n$ 場比賽的排名,還可以再參加 $x$ 場,問從 $1$ 起可能獲得的最長連續名次序列。
思路:
記錄已經獲得的名次,從 $1$ 開始沒有獲得的名次補 $1$,直到不能再補為止。
#include <bits/stdc++.h> using namespace std; void solve() { int n,x;cin>>n>>x; int a[n],cnt[220]={}; for(int &i:a) cin>>i,cnt[i]=1; for(int i=1;x;i++) if(cnt[i]==0) cnt[i]=1,--x; int i=1; while(cnt[i]) ++i; cout<<i-1<<"\n"; } int main() { int t;cin>>t; while(t--) solve(); return 0; }
B. Dreamoon Likes Permutations
題意:
給你一個數組,問從某處分成兩個排列的方案數及方案。
思路:
分界點存在於只出現一次或兩次中后出現的數處,判定條件為前后數列長度等於數組下標對應的長度和各自數列中的最大值,$map$ 記錄分界點,$set$ 增刪,模擬即可。
#include <bits/stdc++.h> using namespace std; void solve() { int n;cin>>n; int a[n];for(int &i:a) cin>>i; vector<int> pos; map<int,int> m; for(int i:a) ++m[i]; set<int> st1,st2; for(int i:a) st2.insert(i); vector<pair<int,int>> ans; for(int i=0;i<n;i++){ if(m[a[i]]==2){ st1.insert(a[i]); --m[a[i]]; continue; } if(st1.size()){ int mx1=*(st1.rbegin()); int mx2=*(st2.rbegin()); if(i==mx1&&mx2==n-i&&mx1==st1.size()&&mx2==st2.size()) ans.emplace_back(i,n-i); } if(m[a[i]]==1){ st1.insert(a[i]); st2.erase(a[i]); } } cout<<ans.size()<<"\n"; for(auto i:ans) cout<<i.first<<' '<<i.second<<"\n"; } int main() { int t;cin>>t; while(t--) solve(); return 0; }
C. Dreamoon Likes Coloring
題意:
一行上有 $n$ 個方格,給出每個顏色染色的長度 $l_i$,可以選擇從 $[1,n-l_i+1]$ 中的一處開始染色,問能否給每個方格染上顏色並且可以看到每一種顏色。
思路:
無解的情況:
- 總染色長度小於方格長度 $n$,最終一定會有方格沒有顏色。
- 某個顏色的最大起點 $n-l_i+1$ 在前面的方格中,因為最大起點的含義是從該起點到最后一個方格都染為該顏色,如果最大起點小於 $i$ 至少會覆蓋一種顏色,因為前 $i-1$ 個顏色至少占用 $i-1$ 個方格,而最大起點之后一直到最后一個方格都會被重新染色。
染色時的情況:
假設每個顏色互不覆蓋能染的最大長度為 $tot\_len$,$n-tot\_len+1$ 即為該顏色段的起點。
- 若 $n-tot\_len+1$ 大於當前方格位置,說明如果從當前方格處開始染色最終一定會有空白的方格,此時至少要從 $n-tot\_len+1$ 處染色才能給每個方格染色。
- 若 $n-tot\_len+1$ 小於當前方格位置,說明接下來一定會有顏色相覆蓋,此時保證每個顏色至少染上自己對應的方格即可。
#include <bits/stdc++.h> using namespace std; int main() { int n,m;cin>>n>>m; int l[n]={}; long long tot_len=0; for(int i=0;i<m;i++) { cin>>l[i]; if(n-l[i]+1<=i)//最大染色起點在前面的方格中 { cout<<"-1"; return 0; } tot_len+=l[i]; } if(tot_len<n)//總染色長度小於n { cout<<"-1"; return 0; } for(int i=0;i<m;i++)//開始染色 { cout<<max(i+1LL,n-tot_len+1)<<" \n"[i==m-1]; tot_len-=l[i]; } return 0; }
D. Dreamoon Likes Sequences
題意:
有一個嚴格遞增的數組$a$,另有一數組 $b$,$b_1=a_1$,$b_i=b_{i-1}\hat{}a_i(i>=2)$,問滿足使 $b$ 嚴格遞增的數組 $a$ 的個數,答案對 $m$ 取模。($a_i≤d,len(a)≥1$)
思路:
因為 $a$ 嚴格遞增,所以若想使 $b$ 也嚴格遞增則同一最高位在 $a$ 中至多出現一次,比如 $2,3$ 只能有一個,因為 $b_i\hat{}2>b_i\hat{}3$,也可以都不選。
所以每個最高位可選的情況有 $min(2^{(v+1)}-1,d)-2^v+1+1$ 個,
第二個$+1$代表不選取最高位為該位的數,也因此最后乘積需要減去一個所有位都沒選取的情況。
#include <bits/stdc++.h> using namespace std; void solve() { int d,m;cin>>d>>m; int b[32]={},t=d; for(int i=0;t;i++){ b[i]=min((1<<(i+1))-1,d)-(1<<i)+2; t>>=1; } long long ans=1; for(int i=0;b[i];i++) ans=ans*b[i]%m; --ans; ans+=m,ans%=m; cout<<ans<<"\n"; } int main() { int t;cin>>t; while(t--) solve(); return 0; }
E. Drazil Likes Heap
建議閱讀:Frozen_Guardian,axiomofchoice。
#include <bits/stdc++.h> using namespace std; #define lc (x<<1) #define rc ((x<<1)+1) #define bigch (a[lc]>a[rc]?lc:rc) #define IO ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr) const int M=(1<<21)+100; int h,g,a[M]; int height(int x){ if(a[x]==0) return 0; return height(bigch)+1; } void del(int x){ if(a[x]==0) return; a[x]=a[bigch]; del(bigch); } vector<int> ans; void dfs(int x,int dep){ if(a[x]==0) return; while(height(x)+dep>g) del(x),ans.push_back(x); dfs(lc,dep+1); dfs(rc,dep+1); } void solve(){ cin>>h>>g; fill(a,a+(1<<(h+1)),0); ans.clear(); for(int i=1;i<(1<<h);i++) cin>>a[i]; dfs(1,0); cout<<accumulate(a,a+(1<<g),0LL)<<"\n"; for(int i:ans) cout<<i<<' '; cout<<"\n"; } int main(){ IO; int t;cin>>t; while(t--) solve(); return 0; }
