Educational Codeforces Round 55 (Rated for Div. 2) ABCD總結
終測前三題900+,終測完三題597,上了35分。總算突破了1700。。。
這次題目簡單題來說偏難。A題9分鐘才寫出來。賽後補了D發現並不是太難。。。
A:一本書有n頁,你現在在x頁,你要翻到y頁,一次只能翻正好d頁。可以從第x頁翻到第n頁或者第1頁(即使不夠正好d頁),再翻到第y頁。不能翻到第y頁輸出-1,否則輸出最少翻幾次。
只需要分上面三種情況看能否整除取最小值就好了。如果都不能整除就是-1。
B:給你一個只包含'G'和'S'的串,你只能最多交換一次兩個字母的位置。求最長連續G序列多長。
統計一下G的總數,維護一下每一個S前面連續多少個G,後面連續多少個G,然後O(n)掃一遍,對於S,考慮能否交換使其左右連線起來。(注意這裡是兩種情況。)
C:有n個學生,m個課題。給你每個學生所選的課題的編號和能力值。
你要選若干學生,組成人數相同的若干組,每一組學生所選課題相同,且任意兩組的課題不能相同。求滿足要求的總最大能力值。
用vector儲存每個課題的學生的能力值,排序,預處理字尾最大值,列舉每一組學生的總數,然後人數夠且字尾>0的課題就可以選了。比賽的時候讀錯題了,以為每組不超過m個人,害我調了一個小時。。。
D:給你n個整數d[i]>=1,這n個點依次編號1~n,讓你構造一個圖,使
1、這個圖的直徑最大
2、這個圖連通
3、這n個點的度數都不超過其對應的d[i]
顯然儘可能的直徑最大,就是先把度不為1的點連成一條鏈,然後度為1的點可以接在兩頭,這樣直徑肯定最大。
然後多餘的度為1的點連到度數還沒夠的點,看看能不能全連上即可。
因此用三個vector,第一個vector儲存度為1的點的下標,第二個第三個都是pair,分別儲存度和下標,以及相連的點的編號,然後按上面思路寫就行了。注意no情況的判斷。
程式碼:
#include<bits/stdc++.h> #define ll long long #define mp make_pair using namespace std; const int maxn=500+10; int n,k; vector<int>yi; vector< pair<int,int> >duo,ans; int cnt,tmp,flag; int d[maxn]; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&k); if(k==1) yi.push_back(i); else duo.push_back(mp(k,i)); } if(!duo.size()) {puts("NO");return 0;} tmp=duo.size()-1; for(int i=0;i<duo.size()-1;i++) { ans.push_back(mp(duo[i].second,duo[i+1].second)); d[duo[i].second]++; d[duo[i+1].second]++; } if(yi.size()) { ans.push_back(mp(yi.back(),duo[0].second)); d[yi.back()]++; d[duo[0].second]++; yi.pop_back(); tmp++; if(yi.size()) { ans.push_back(mp(yi.back(),duo.back().second)); d[yi.back()]++; d[duo.back().second]++; yi.pop_back(); tmp++; } } int i=0; while(yi.size()&&i<duo.size()) { if(d[duo[i].second]<duo[i].first) { ans.push_back(mp(yi.back(),duo[i].second)); d[duo[i].second]++; yi.pop_back(); } else i++; } if(yi.size()) {puts("NO");return 0;} printf("YES %d\n",tmp); printf("%d\n",ans.size()); for(int i=0;i<ans.size();i++) { printf("%d %d\n",ans[i].first,ans[i].second); } return 0; }