Codeforces Round #486 (Div. 3) A-F題解

A.題意:100個數字,大小100,問可否從中選出k個不同數字,輸出位置
思路:map.count
代碼:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;

int main(){
    IO;
    int n,k;cin>>n>>k;
    vector<int> a;
    map<int,int>mp;
    forn(i,n){
        int x;cin>>x;
        if(!mp[x]) a.push_back(i+1);
        mp[x]++;
    }
    if(a.size()>=k){
        cout<<"YES"<<'\n';
        forn(i,k) cout<<a[i]<<' ';
    } else cout<<"NO"<<'\n';
    return 0;
}

B.題意:給100個長度爲100的字符串,排序使得前面的每一個字符串前面的字符串爲他的的子串。
思路:暴力就可以了,不暴力可以dp+kmp做,substr可以減少代碼量,用法爲string.(起始位置,長度)
代碼:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;

vector<string>s[100];
map<int,pair<int,int> >mp;

int main(){
    IO;
    int n;cin>>n;
    forn(i,n){
        int m;cin>>m;
        vector<int>a(m);
        int sum = 0;
        forn(j,m){
            cin>>a[j];
            sum+=a[j];
        }
        forn(j,m)if(mp.count(sum-a[j])){
            cout<<"YES"<<'\n';
            auto ans = mp[sum-a[j]];
            cout<< ans.first+1<<' '<<ans.second+1<<'\n';
            cout<<i+1<<' '<<j+1<<'\n';
            return 0;
        }
        forn(j,m)if(!mp.count(sum-a[j]))mp[sum-a[j]] = {i,j};
    }
    cout<<"NO"<<'\n';
    return 0;
}

C.題意:2e5個數組,共最多2e5個數,能否刪除某兩個數組的一個數字,使得這兩個數組的sum值相同。
思路:map存,出現答案return
代碼:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;

vector<string>s[100];
map<int,pair<int,int> >mp;

int main(){
    IO;
    int n;cin>>n;
    forn(i,n){
        int m;cin>>m;
        vector<int>a(m);
        int sum = 0;
        forn(j,m){
            cin>>a[j];
            sum+=a[j];
        }
        forn(j,m)if(mp.count(sum-a[j])){
            cout<<"YES"<<'\n';
            auto ans = mp[sum-a[j]];
            cout<< ans.first+1<<' '<<ans.second+1<<'\n';
            cout<<i+1<<' '<<j+1<<'\n';
            return 0;
        }
        forn(j,m)if(!mp.count(sum-a[j]))mp[sum-a[j]] = {i,j};
    }
    cout<<"NO"<<'\n';
    return 0;
}

D.
題意:2e5個數,問最多取多少個數字使得各個數字兩兩差爲2的冪。
思路:取一個數,它右邊最多取一個,左邊最多取一個。假設取了兩個那麼必然和本數差2^k和2的冪次方,可以看爲二進制的兩個不同位置的1,那麼這兩個差肯定是多個1,除了最小那兩個以外。當我們考慮最小的兩個會發現,左邊取不了。所以最多三個,知道這個定理之後就可以map記錄然後枚舉。
代碼:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)

map<ll,int>mp;
int main(){ 
    IO;
    int n;cin>>n;vector<ll>a(n);forn(i,n){
        int x; cin>>x;a[i] = x;
        mp[x] = 1;
    }
    forn(j,n){
        forn(i,32){
            ll x = 1ll<<i;
            //if(a[j]==5&&i==1) cerr<<a[j]<<' '<<x<<' '<<a[j]+x<<' '<<a[j]+x<<'\n';
            if(mp.count(x+a[j])&&mp.count(a[j]-x)){
                cout<<3<<'\n';
                cout<<a[j]-x<<' '<<a[j]<<' '<<a[j]+x<<'\n';
                return 0;
            }
        }
    }
    forn(j,n){
        forn(i,32){
            ll x = 1ll<<i;
            if(mp.count(x+a[j])){
                cout<<2<<'\n';
                cout<<a[j]+x<<' '<<a[j]<<'\n';
                return 0;
            }
            if(mp.count(a[j]-x)){
                cout<<2<<'\n';
                cout<<a[j]-x<<' '<<a[j]<<'\n';
                return 0;
            }
        }
    }
    cout<<1<<'\n'<<a[0]<<'\n';
    return 0;
}

E.
題意:給一個數字經過一些操作使得它可以被25整除,每次操作可以使相鄰兩數直接交換位置,不能有前導0,求最小操作次數。
思路:顯然末尾只要有00,50,25,75就可以了,那麼分類討論,先移動最近的0或5,在找最近的另一個數字。比如50267,要考慮前導0,那麼我們最後判斷有前導0的情況找按順序找第一個非0的數。加上去取min即可。
代碼:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int inf = 0x3f3f3f3f;
int main(){
    IO;
    string s,m;cin>>s;
    m = s;
    int ans = inf,res = inf,pos = 0;
    bool ok1 = 0,ok2 = 0;
    for(int i = m.size()-1;i>=0;i--){
        if(m[i]=='5'){
            ok1 = 1;
            res = 0;
            res+=m.size()-i-1;
            pos = i;
            break;
        }
    }
    if(res!=inf){
        for(int i = pos+1;i<m.size();i++) swap(m[i],m[i-1]);
        for(int i = m.size()-2;i>=0;i--){
            if(m[i]=='2'||m[i]=='7'){
                ok2 = 1;
                res+=m.size()-i-2;
                pos = i;
                break;
            }
        }
        for(int i = pos+1;i<m.size()-1;i++)swap(m[i],m[i-1]);
        if(m[0]=='0'){
            for(int i = 0;i<m.size()-2;i++){
                if(m[i]!='0'){
                    res+=i;
                    m[0]='#';
                    break;
                }
            }
        }
    }
    if(m[0]!='0'&&ok1&&ok2) ans = res;
    res = inf,m = s,ok1=ok2 = 0;
    for(int i = m.size()-1;i>=0;i--){
        if(s[i]=='0'){
            ok1 = 1;
            res = 0;
            res+=m.size()-i-1;
            pos = i;
            break;
        }
    }
    if(res!=inf){
        for(int i = pos+1;i<m.size();i++) swap(m[i],m[i-1]);
        for(int i = m.size()-2;i>=0;i--){
            if(m[i]=='5'||m[i]=='0'){
                ok2 = 1;
                res+=m.size()-i-2;
                pos = i;
                break;
            }
        }
        for(int i = pos+1;i<m.size()-1;i++)swap(m[i],m[i-1]);
        if(m[0]=='0'){
            for(int i = 0;i<m.size()-2;i++){
                if(m[i]!='0'){
                    res+=i;
                    m[0]='#';
                    break;
                }
            }
        }
    }
    if(m[0]!='0'&&ok1&&ok2) ans = min(ans,res);
    if(ans!=inf) cout<<ans<<'\n';
    else cout<<-1<<'\n';
    return 0;
}

F.
題意:一條路從1點走到a點,一次只移動1格。現在有n個區間有雨,你在下雨區間必須打傘。現在上帝給你在m個點都放了傘,每把傘有它的放的位置pi和你的壞感度wi。當你拿一把傘走了1個距離,那麼你的心情-wi。你可以隨時扔掉傘,如果pi有傘你可以撿傘換傘。問心情最少-多少。
思路:dpij i表示走到第幾個點,j表示此時手上用第j個雨傘
每次可以轉移這三種:

  1. i的時候沒有雨扔掉傘dpi-1j轉移到dpi0
  2. 繼續打傘dpi-1j轉移到dpij
  3. i-1處有新傘換傘dpi-1j轉移到dpia[i-1](a表示傘)
    代碼:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int maxn = 2005;
const int inf = 0x3f3f3f3f;
bool vis[maxn];
int p[maxn],dp[maxn][maxn];

int main(){ 
    IO;
    int e,n,m;cin>>e>>n>>m;
    memset(dp,inf,sizeof(dp));
    forn(i,n){
        int l,r;cin>>l>>r;
        for(int i = l+1;i<=r;i++) vis[i] = 1;
    }
    vector<int>w(m+1);
    w[0] = inf;
    for1(i,m){
        int x,y;cin>>x>>y; 
        w[i] = y; 
        if(w[p[x]]>y) p[x] = i;
    }
    dp[0][0] = 0;
    for1(i,e){
        for(int j = 0;j<=m;j++){
            if(!vis[i])dp[i][0] = min(dp[i][0],dp[i-1][j]);
            if(j) dp[i][j] = min(dp[i][j],dp[i-1][j]+w[j]);
            if(p[i-1]) dp[i][p[i-1]] = min(dp[i][p[i-1]],dp[i-1][j]+w[p[i-1]]);
        }
    }
    int ans = inf;
    forn(i,m+1) ans = min(ans,dp[e][i]);
    if(ans==inf) cout<<-1<<'\n';
    else cout<<ans<<'\n';
    return 0; 
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章