1. 程式人生 > 實用技巧 >Codeforces Round #542題解

Codeforces Round #542題解

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];
    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; }
View Code

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;
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; }
View Code

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