Codeforces Round #631 (Div. 2)
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; }