A题
如果是0大于一半,无解,否则取多的一边即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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]; int cnt1=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即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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 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,不然根据直线最短距离,我们枚举两个连通块里的点计算最小值
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }
D1题
先做的D1题,观察到数据范围很小,直接暴力模拟就能通过,这里的想法是因为每个点只能上一个,并且都要绕一圈才能上第二个,所以每个位置独立,并按照离当前位置远近贪心排序
D1用的是vector直接模拟
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }
D2题
原理与上题相同,因为不能无脑模拟,再仔细想一想性质发现其实只有每个位置的最后一个点有用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }
E题
对于构造合法方案题,我认为一定要从边界构造开始,也就是情况越简单越好,这样讨论就不会很复杂,那么其实我们当作2000个点,只要最后两个点有值并按照模数计算一下
就能获取正确答案,做构造题的时候,极端条件或者题目通性感觉比较好做一点
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }