Codeforces Round #672 (Div. 2)
A - Cubes Sorting
冒泡排序交換次數等于逆序對數,嚴格降序需要交換n(n?1)2\frac{n(n-1)}{2}2n(n?1)?次才能升序排列,由此只需要判斷原數組是否嚴格降序即可。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0) #pragma GCC optimize(2) #include<iostream> #include<algorithm> using namespace std; const int N=500010; int a[N]; int n; int main() {IO;int T=1;cin>>T;while(T--){bool ok=1;cin>>n;for(int i=1;i<=n;i++){cin>>a[i];if(i>1&&a[i]>=a[i-1]) ok=0;}if(ok) cout<<"NO\n";else cout<<"YES\n";}return 0; }B - Rock and Lever
按位考慮,隨便搞搞
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0) #pragma GCC optimize(2) #include<iostream> #include<algorithm> using namespace std; typedef pair<int,int> pii; typedef long long ll; const int N=500010; int a[N]; int cnt[40]; int n; int main() {IO;int T=1;cin>>T;while(T--){bool ok=1;cin>>n;memset(cnt,0,sizeof cnt);for(int i=1;i<=n;i++){cin>>a[i];bool ok=1;for(int j=31;j>=0;j--)if(ok&&(a[i]>>j&1)){cnt[j]++;ok=0;break;}}ll res=0;for(int i=31;i>=0;i--)if(cnt[i])res+=1ll*cnt[i]*(cnt[i]-1)/2;cout<<res<<'\n';}return 0; }C1 - Pokémon Army (easy version)
不帶修改,直接dp掃一遍。
狀態表示:f(i,0)f_{(i,0)}f(i,0)?考慮前iii個數,并且選擇第iii個數狀態是+,f(i,1)f_{(i,1)}f(i,1)?考慮前iii個數,并且選擇第iii個數狀態是-
狀態轉移:f(i,0)=max(f(i,0),f(k,1)+ai)f_{(i,0)}=max(f_{(i,0)},f_{(k,1)}+a_i)f(i,0)?=max(f(i,0)?,f(k,1)?+ai?),f(i,1)=max(f(i,1),f(k,0)?ai)f_{(i,1)}=max(f_{(i,1)},f_{(k,0)}-a_i)f(i,1)?=max(f(i,1)?,f(k,0)??ai?),(1<k<i1<k<i1<k<i)只需要在維護2個前綴最大值即可O(n)O(n)O(n)得到答案。
Pokémon Army (hard version)
用線段樹維護fff數組即可,對于線段樹每一個區間維護數組f[2][2]f[2][2]f[2][2]。
f[0][0]f[0][0]f[0][0]表示序列開頭+,結尾+。
f[0][1]f[0][1]f[0][1]表示序列開頭+,結尾-。
f[1][0]f[1][0]f[1][0]表示序列開頭-,結尾+。
f[1][1]f[1][1]f[1][1]表示序列開頭-,結尾-。
D - Rescue Nibel!
先上課去了,晚上回來寫。第一次數組開小了還re了
先把每個區間的左端點和右端點拆開記錄下來,然后排個序(注意:先按照位置排序,按照左端點優先原則排序)借用掃描線的思想掃描整個序列。
掃描的過程中,如果到一個左端點說明目前有一盞燈在此時刻點亮那么對答案的貢獻就是在需要從前面點亮的燈中選擇k?1k-1k?1盞燈,維護前面點亮燈的數量只需要維護一個cnt即可,那么對答案的貢獻即Ccntk?1C_{cnt}^{k-1}Ccntk?1?,然后更新cnt即可,如果掃描到一個右端點不難發現對答案沒有貢獻,只需要維護cnt即可。
計算Ccntk?1C_{cnt}^{k-1}Ccntk?1?的過程中由于既要取模又有除法需要提前預處理階乘和逆元。
E - Battle Lemmings
我還是不會難的dp
whd大佬視頻題解
為什么能用dp?
首先有一點非常重要:無論如何移動1,所有1的相對位置并不會改變。因此考慮答案的集合肯定是將這些1不改變相對位置的情況下排到某些位置,而代價即移動的步數可以通過原先位置和當前位置算出來,那么如果我們逐一考慮每一個1最終的位置不難發現這個問題是無后效性的。
如何算出答案?
最終要求算一個很奇怪的東西,就是兩個0之間只要存在1的對數,發現非常難以計算,我們轉化問題考慮反面:哪些0不會對答案有貢獻?不難發現只要連續的0兩兩配對都不會對答案有貢獻,我們只需要用總數目減去這些不滿足的即可。
狀態表示:f(i,j,k)f_{(i,j,k)}f(i,j,k)?考慮前iii個位置,目前考慮了前jjj個111的位置,代價即交換次數是kkk的集合。
狀態轉移:考慮第j+1j+1j+1個111的位置,枚舉i+1→ni+1\to ni+1→n,進行答案更新,這里是向后更新未知狀態。
時間復雜度:O(n5)O(n^5)O(n5),但是常數非常小,再加上cf強大的評測雞,跑的并不慢155ms
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0) #pragma GCC optimize(2) #include<set> #include<map> #include<cmath> #include<queue> #include<string> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef pair<int,int> pii; typedef long long ll; const int N=83,INF=0x3f3f3f3f; int f[N][N][N*(N-1)/2]; int n,a[N],pos[N],cnt1; int main() {IO;int T=1;//cin>>T;while(T--){cin>>n;for(int i=1;i<=n;i++){cin>>a[i];if(a[i]) pos[++cnt1]=i;}int m=n*(n-1)/2;memset(f,0x3f,sizeof f);f[0][0][0]=0;for(int i=0;i<=n;i++)for(int j=0;j<cnt1;j++)for(int k=0;k<=m;k++){if(f[i][j][k]>=INF) continue;for(int p=i+1;p<=n;p++){int now=abs(p-pos[j+1]);if(now+k>m) continue;int cost=max(p-i-1,0)*max(p-i-2,0)/2;if(j+1==cnt1) cost+=(n-p)*(n-p-1)/2;f[p][j+1][k+now]=min(f[p][j+1][k+now],f[i][j][k]+cost);}}int cnt0=n-cnt1;for(int i=0;i<=m;i++){int res=INF;for(int j=1;j<=n;j++){if(i) f[j][cnt1][i]=min(f[j][cnt1][i],f[j][cnt1][i-1]);res=min(res,f[j][cnt1][i]);}if(!cnt1) cout<<0<<' ';else cout<<cnt0*(cnt0-1)/2-res<<' ';}}return 0; }總結
以上是生活随笔為你收集整理的Codeforces Round #672 (Div. 2)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 八十年代流行歌曲 流行歌曲推荐
- 下一篇: Codeforces Round #67