Codeforces Round #542題解
阿新 • • 發佈:2020-12-18
A題
如果是0大於一半,無解,否則取多的一邊即可
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=5e5+10; int a[N]; int main(){ ios::sync_with_stdio(false); int n; int i; cin>>n; for(i=1;i<=n;i++) cin>>a[i]; intView Codecnt1=0,cnt2=0; for(i=1;i<=n;i++){ if(a[i]<0) cnt1++; if(a[i]>0) cnt2++; } n=(n+1)/2; if(cnt1<n&&cnt2<n){ cout<<0<<endl; } else{ if(cnt1<n){ cout<<1<<endl; }else{ cout<<-1<<endl; } } return 0; }
B題
你會發現,因為必須要按照順序走,因此肯定是先走到兩個1,再走到兩個2,這樣整體的變化其實就是兩種情況a[i-1][1]->a[i][1],a[i-1][2]->a[i][2],或者a[i-1][2]->a[i][1],a[i-1][1]->a[i][2]
對於兩種取min即可
#include<bits/stdc++.h> using namespace std; typedefView Codelong long ll; typedef pair<int,int> pll; const int N=5e5+10; int a[N]; int vis[N]; int pos[N][2]; int main(){ ios::sync_with_stdio(false); int n; cin>>n; n*=2; int i; for(i=1;i<=n;i++){ cin>>a[i]; if(pos[a[i]][1]){ pos[a[i]][2]=i; } else{ pos[a[i]][1]=i; } } ll ans=pos[1][1]-1+pos[1][2]-1; for(i=2;i<=n/2;i++){ ans+=min(abs(pos[i][1]-pos[i-1][1])+abs(pos[i][2]-pos[i-1][2]),abs(pos[i][1]-pos[i-1][2])+abs(pos[i][2]-pos[i-1][1])); } cout<<ans<<endl; return 0; }
C題
顯然劃分連通塊,如果在同一個連通塊裡面說明為0,不然根據直線最短距離,我們列舉兩個連通塊裡的點計算最小值
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=5e5+10; int sx,sy,tx,ty; int s[1010][1010]; vector<pll> g[N]; int vis[100][100]; int cnt=0; int dx[4]={-1,0,1,0}; int dy[4]={0,1,0,-1}; int n; map<pll,int> m1; void dfs(int a,int b){ int i; vis[a][b]=1; g[cnt].push_back({a,b}); m1[{a,b}]=cnt; for(i=0;i<4;i++){ int x=a+dx[i]; int y=b+dy[i]; if(x>=1&&x<=n&&y>=1&&y<=n){ if(!vis[x][y]&&(s[x][y]==0)){ dfs(x,y); } } } } int main(){ ios::sync_with_stdio(false); int i,j; cin>>n; cin>>sx>>sy>>tx>>ty; for(i=1;i<=n;i++){ for(j=1;j<=n;j++){ char c; cin>>c; if(c=='0') s[i][j]=0; else s[i][j]=1; } } for(i=1;i<=n;i++){ for(j=1;j<=n;j++){ if(s[i][j]==0&&!vis[i][j]){ cnt++; dfs(i,j); } } } if(m1[{sx,sy}]==m1[{tx,ty}]){ cout<<0<<endl; } else{ int ans=1e9; for(auto x:g[m1[{sx,sy}]]){ for(auto y:g[m1[{tx,ty}]]){ int d=(x.first-y.first)*(x.first-y.first)+(x.second-y.second)*(x.second-y.second); ans=min(ans,d); } } cout<<ans<<endl; } return 0; }View Code
D1題
先做的D1題,觀察到資料範圍很小,直接暴力模擬就能通過,這裡的想法是因為每個點只能上一個,並且都要繞一圈才能上第二個,所以每個位置獨立,並按照離當前位置遠近貪心排序
D1用的是vector直接模擬
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=5e5+10; int a[N],b[N]; vector<int> num; vector<pll> g[N]; vector<pll> tmp[N]; int vis[1010]; bool cmp(pll a,pll b){ return a.second>b.second; } int main(){ ios::sync_with_stdio(false); int n,m; cin>>n>>m; int i,j; for(i=1;i<=m;i++){ cin>>a[i]>>b[i]; int x=b[i]-a[i]; if(x<0) x+=n; g[a[i]].push_back({b[i],x}); } for(i=1;i<=n;i++){ sort(g[i].begin(),g[i].end(),cmp); } for(int i=1;i<=n;i++){ int pos=i; int cnt=0; int ans=0; num.clear(); for(j=1;j<=n;j++) tmp[j]=g[j]; while(1){ if(tmp[pos].size()){ num.push_back(tmp[pos][0].first); tmp[pos].erase(tmp[pos].begin()); } for(int i=0;i<(int)num.size();i++){ int x=num[i]; if(x==pos){ cnt++; } } vector<int> dd; dd.clear(); for(auto x:num){ if(x!=pos) dd.push_back(x); } num=dd; if(cnt==m){ cout<<ans<<" "; break; } pos++; ans++; if(pos>n) pos-=n; } } return 0; }View Code
D2題
原理與上題相同,因為不能無腦模擬,再仔細想一想性質發現其實只有每個位置的最後一個點有用
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=5e5+10; int a[N],b[N]; vector<int> num; vector<pll> g[N]; vector<pll> tmp[N]; int vis[1010]; bool cmp(pll a,pll b){ return a.second>b.second; } int main(){ ios::sync_with_stdio(false); int n,m; cin>>n>>m; int i,j; for(i=1;i<=m;i++){ cin>>a[i]>>b[i]; int x=b[i]-a[i]; if(x<0) x+=n; g[a[i]].push_back({b[i],x}); } for(i=1;i<=n;i++){ sort(g[i].begin(),g[i].end(),cmp); } for(int i=1;i<=n;i++){ int ans=0; for(j=1;j<=n;j++){ if((int)g[j].size()==0) continue; int op=j-i; if(op<0) op+=n; int cnt=op; cnt+=((int)g[j].size()-1)*n; int x=g[j][(int)g[j].size()-1].first-j; if(x<0) x+=n; cnt+=x; ans=max(ans,cnt); } cout<<ans<<" "; } cout<<endl; return 0; }View Code
E題
對於構造合法方案題,我認為一定要從邊界構造開始,也就是情況越簡單越好,這樣討論就不會很複雜,那麼其實我們當作2000個點,只要最後兩個點有值並按照模數計算一下
就能獲取正確答案,做構造題的時候,極端條件或者題目通性感覺比較好做一點
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=5e5+10; int main(){ ios::sync_with_stdio(false); int k,a; cin>>k; a=2000-k%2000+998000; cout<<2000<<endl; int i; for(i=1;i<=1998;i++){ cout<<0<<" "; } cout<<-a+(k+a)/2000<<" "<<a<<endl; return 0; }View Code