CF#692 div2
阿新 • • 發佈:2020-12-22
技術標籤:比賽
A 從後往前找連續)最長長度判斷是否大於n/2即可
B 一個數字只會出現1-9,而1-9的最小公倍數為7560 所以你最多自增7560個數後必能找到符合條件的數,所以暴力模擬即可
C 因為m小於n所以必能找到符合條件的,我們想想後會發現一些規律
出現的點分為這幾種情況:
1.本身就在斜對角線上,無需挪動,不管他就好
2.幾個點互為環的情況例如 2,3 3,4, 4,5 5,2 這樣得吧一個點換到空行去,然後....(不會講了,反正這種情況步數是5,(環長度+1))
3.幾個點為鏈情況 2,3 3,4 4,5 5,6 這樣步數為4(鏈長度)(一個點也算鏈)
那麼很明顯,先連邊建圖,再找每條鏈長度,每個環大小即可
程式碼如下(還是建議你們想通了自己寫,我的碼風....一言難盡)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+107; #define int ll vector<int>son[N]; int hang[N]; int lie[N]; pair<int,int>a[N]; int vis[N];///標記跑過的點 void solve() { int n,m; cin>>n>>m; for(int i=1;i<=n;i++) hang[i]=lie[i]=0; for(int i=1;i<=m;i++) { son[i].clear(); vis[i]=0; cin>>a[i].first>>a[i].second; if(a[i].first==a[i].second) {vis[i]++;continue;} lie[a[i].second]=i; hang[a[i].first]=i; } for(int i=1;i<=n;i++) { if(hang[i]&&lie[i]) { int a1=hang[i],a2=lie[i]; son[a1].push_back(a2); son[a2].push_back(a1); } } /*for(int i=1;i<=m;i++) { cout<<i<<':'; for(int j=0;j<son[i].size();j++) cout<<son[i][j]<<' ';cout<<endl; }*/ int ans=0; for(int i=1;i<=m;i++) { if(vis[i]) continue; vis[i]++; if(son[i].size()==0) {ans++;continue;}///鏈只有一個點情況 int d=son[i][0]; int cnt=1; int last=i; while(d!=i) { vis[d]++;cnt++; if(son[d].size()==1) break; if(son[d][0]==last) last=d, d=son[d][1]; else last=d,d=son[d][0]; } if(d==i) ans+=cnt+1;///環 else///鏈 { if(son[i].size()==2)///當前點不為鏈端點 { d=son[i][1]; last=i; while(d!=i) { vis[d]++;cnt++; if(son[d].size()==1) break; if(son[d][0]==last) last=d, d=son[d][1]; else last=d,d=son[d][0]; } } ans+=cnt; } } cout<<ans<<endl; } signed main() { int zs; cin>>zs; while(zs--) solve(); } /* 1 5 4 4 5 5 1 2 2 3 3 */
D 看了題解,最優的結果是所有的?前部分全為0後部分全為1或全部分全為1後部分全為0,但是我不知道為什麼這樣就對了,字首和維護,列舉第幾個?開始,找最小ans就完事了。