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; 
}
posted @ 2019-08-29 11:18  AlexPanda  阅读(92)  评论(0编辑  收藏  举报