1. 程式人生 > ># Codeforces Round #529(Div.3)個人題解

# Codeforces Round #529(Div.3)個人題解

Codeforces Round #529(Div.3)個人題解

前言: 閒來無事補了前天的cf,想著最近刷題有點點怠惰,就直接一場cf一場cf的刷算了,以後的題解也都會以每場的形式寫出來


A. Repeating Cipher

傳送門

題意:第一個字母寫一次,第二個字母寫兩次,依次遞推,求原字串是什麼

題解:1、2、3、4,非常明顯的d=1的等差數列,所以預處理一個等差數列直接取等差數列的每一項即可

程式碼:

#include<bits/stdc++.h>
using namespace std;
int num[100000];
void init(){
    int ans=0;
    for(int i=1;i<=1000;i++){
        ans+=i;
        num[i]=ans;
    }
    return;
}
char str[10000];
int main(){
    int n;
    init();
    scanf("%d %s",&n,str+1);
    int tmp=1;
    while(num[tmp]!=n){
        tmp++;
    }
    for(int i=1;i<=tmp;i++){
        cout<<str[num[i]];
    }
    cout<<endl;
}

B. Array Stabilization

傳送門

題意:給你一串數字,要你刪除一個數最小化這串數字中最大值-最小值的差

題解:用multiset存一下,然後討論刪去最大的數更好還是刪去最小的數更好

程式碼:

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <bitset>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define PI acos(-1)
#define eps 1e-8
#define fuck(x) cout<<#x<<" = "<<x<<endl;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define FIN freopen("input.txt","r",stdin);
#define FOUT freopen("output.txt","w+",stdout);
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int, int> PII;
const int maxn = 3e5 + 5;
const LL INF = 1e18 + 7;
const ull mod = 9223372034707292160;
LL gcd(LL a, LL b) {return b ? gcd(b, a % b) : a;}
LL lcm(LL a, LL b) {return a / gcd(a, b) * b;}
LL powmod(LL a, LL b, LL MOD) {LL ans = 1; while (b) {if (b % 2)ans = ans * a % MOD; a = a * a % MOD; b /= 2;} return ans;}
double dpow(double a, LL b) {double ans = 1.0; while (b) {if (b % 2)ans = ans * a; a = a * a; b /= 2;} return ans;}
multiset<int> s;
int main() {
#ifndef ONLINE_JUDGE
    FIN
#endif
    int n;
    cin >> n;
    int x;
    for (int i = 0; i < n; i++) {
        scanf("%d", &x);
        s.insert(x);
    }
    multiset<int>::iterator it;
    it = s.begin();
    int minn = *it;
    it = s.end();
    it--;
    int maxx = *it;
    if (s.count(minn) != 1 && s.count(maxx) != 1) {
        cout << maxx - minn << endl;
    } else if (s.count(minn) == 1 && s.count(maxx) == 1) {
        it = s.begin();
        it++;
        int tmp1 = *it;
        it = s.end();
        it--;
        it--;
        int tmp2 = *it;
        int ans1 = maxx - tmp1;
        int ans2 = tmp2 - minn;
        cout << min(ans1, ans2) << endl;
    } else {
        if (s.count(minn) == 1) {
            it = s.begin();
            it++;
            cout << maxx - *it << endl;
        } else {
            it = s.end();
            it--;
            it--;
            cout << *it - minn << endl;
        }
    }
}

C. Powers Of Two

傳送門

題意:給你一個數n,要求你用k個2的冪次數去拼出這個數,如果不能輸出-1

題解:先將n轉換為相對應的二進位制數 ,如果n的二進位制數中的1的個數大於k,顯然是沒有解的,如果n的二進位制數中的1的個數小於1,那麼就把每一個大於2的數分解(x->x/2+x/2),湊出k個1即可,最後輸出 一下就行

程式碼

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <bitset>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define PI acos(-1)
#define eps 1e-8
#define fuck(x) cout<<#x<<" = "<<x<<endl;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define FIN freopen("input.txt","r",stdin);
#define FOUT freopen("output.txt","w+",stdout);
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int, int> PII;
const int maxn = 3e5 + 5;
const LL INF = 1e18 + 7;
const ull mod = 9223372034707292160;
LL gcd(LL a, LL b) {return b ? gcd(b, a % b) : a;}
LL lcm(LL a, LL b) {return a / gcd(a, b) * b;}
LL powmod(LL a, LL b, LL MOD) {LL ans = 1; while (b) {if (b % 2)ans = ans * a % MOD; a = a * a % MOD; b /= 2;} return ans;}
double dpow(double a, LL b) {double ans = 1.0; while (b) {if (b % 2)ans = ans * a; a = a * a; b /= 2;} return ans;}

int main() {
#ifndef ONLINE_JUDGE
    FIN
#endif
    LL n, k;
    cin >> n >> k;
    if (k > n) {
        cout << "NO" << endl;
    } else {
        multiset<int> ans;
        multiset<int>::iterator it;

        for (int i = 0; i < 30; i++)
            if ((n >> i) & 1)
                ans.insert(i);
        if (ans.size() > k)
        {
            cout << "NO";
            return 0;
        }
        cout << "YES\n";
        while ((int)ans.size() < k)
        {
            it = ans.end();
            it--;
            int x = (*it);
            ans.erase(ans.lower_bound(x));
            ans.insert(x - 1);
            ans.insert(x - 1);
        }
        for (it = ans.begin(); it != ans.end(); it++)
            cout << (1 << *it) << " ";
        return 0;
    }
}

D. Circular Dance

傳送門

題意:n個人圍成一圈,每個人報出接下來兩個人的序號,但是不保證按照順序來,求解這一圈人的編號順序,題目有spj

題解:將每個人報的編號想成兩個點,然後就行成了一個圖的關係,那麼現在我們就只需要判定這個圖的連通性即可

程式碼:

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <bitset>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define PI acos(-1)
#define eps 1e-8
#define fuck(x) cout<<#x<<" = "<<x<<endl;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define FIN freopen("input.txt","r",stdin);
#define FOUT freopen("output.txt","w+",stdout);
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int, int> PII;
const int maxn = 3e5 + 5;
const LL INF = 1e18 + 7;
const ull mod = 9223372034707292160;
LL gcd(LL a, LL b) {return b ? gcd(b, a % b) : a;}
LL lcm(LL a, LL b) {return a / gcd(a, b) * b;}
LL powmod(LL a, LL b, LL MOD) {LL ans = 1; while (b) {if (b % 2)ans = ans * a % MOD; a = a * a % MOD; b /= 2;} return ans;}
double dpow(double a, LL b) {double ans = 1.0; while (b) {if (b % 2)ans = ans * a; a = a * a; b /= 2;} return ans;}
vector<int> ans;
vector<int> mp[maxn];
bool check(int a, int b) {
    for (int i = 0; i < mp[a].size(); i++) {
        if (mp[a][i] == b) {
            return 1;
        }
    }
    return 0;
}
int get_next(int x){
    int v1=mp[x][0];
    int v2=mp[x][1];
    if(check(v1,v2)){
        return v1;
    }
    return v2;
}
int main() {
#ifndef ONLINE_JUDGE
    FIN
#endif
    int n;
    scanf("%d", &n);
    int u, v;
    for (int i = 1; i <= n; i++) {
        scanf("%d%d", &u, &v);
        mp[i].push_back(u);
        mp[i].push_back(v);
    }
    if (n == 3) {
        cout << "1 2 3" << endl;
        return 0;
    }

    ans.push_back(1);
    while (ans.size() < n) {
        int val = ans.back();
        int nxt = get_next(val);
        ans.push_back(nxt);
    }

    for (int i = 0; i < ans.size(); i++) {
        if (i)
            cout << " ";
        cout << ans[i];
    }
    cout << endl;
}

E. Almost Regular Bracket Sequence

傳送門

題意:給你一個括號序列,你需要翻轉其中一個括號使得括號序列合法,求應該翻哪個,有spj

題解:我們可以用字首和來很好的解決括號匹配問題,首先我們規定‘(’是1,‘)’是-1求出這個序列的字首和,然後用一個數組來記錄從後往前的字首和的最小值,最後從前往後掃一遍,判斷翻轉這個位置是否能夠使得序列合法即可

程式碼

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+5;
string str;
int n;
bool check(string str){
    int len=str.length();
    int tmp=len/2;
    for(int i=0;i<tmp;i++){
        if(str[i]!=str[len-i]) return 0;
    }
    return 1;
}
int sum[maxn];
int minn[maxn];
int main(){
    cin>>n>>str;
    sum[0]=0;
    for(int i=0;i<n;i++){
        if(str[i]=='(') sum[i+1]=sum[i]+1;
        else if(str[i]==')') sum[i+1]=sum[i]-1;
    }
    minn[n]=sum[n];
    for(int i=n-1;i>=0;i--){
        minn[i]=min(minn[i+1],sum[i]);
    }
    int ans=0;
    for(int i=0;i<n;i++){
        if(sum[i]<0) break;
        int tmp=sum[i];
        if(str[i]==')'){
            tmp++;
        }else if(str[i]=='('){
            tmp--;
        }
        if(tmp<0) continue;
        if(sum[n]-sum[i+1]+tmp!=0) continue;
        if(minn[i+1]-sum[i+1]+tmp<0) continue;
        ans++;
    }
    cout<<ans<<endl;

}

F. Make It Connected

傳送門

題意:給你一個無向圖,有n個點,每個點有一個權值,從a點走到b點的花費是a、b的權值和,有m條邊可以連線,如果連線u和v則花費w的權值,當然也可以選擇不連,求使得這個圖聯通的最小花費

題解:我們找到一個起點,要想使得這個生成這個圖的花費最小,那麼起點一定是權值最小的那個,連邊時將這個起點和所有的點連線起來,然後最後跑一個最小生成樹即可

程式碼

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <bitset>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define PI acos(-1)
#define eps 1e-8
#define fuck(x) cout<<#x<<" = "<<x<<endl;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define FIN freopen("input.txt","r",stdin);
#define FOUT freopen("output.txt","w+",stdout);
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int, int> PII;
const int maxn = 3e5 + 5;
const LL INF = 1e18 + 7;
const ull mod = 9223372034707292160;
LL gcd(LL a, LL b) {return b ? gcd(b, a % b) : a;}
LL lcm(LL a, LL b) {return a / gcd(a, b) * b;}
LL powmod(LL a, LL b, LL MOD) {LL ans = 1; while (b) {if (b % 2)ans = ans * a % MOD; a = a * a % MOD; b /= 2;} return ans;}
double dpow(double a, LL b) {double ans = 1.0; while (b) {if (b % 2)ans = ans * a; a = a * a; b /= 2;} return ans;}

int n, m;
LL a[maxn];
struct EDGE {
    int u, v;
    LL w;
    bool operator < (const EDGE&a) {
        return w < a.w;
    }
}edge[maxn<<2];
int f[maxn];
int find(int x){
    return x==f[x]?x:f[x]=find(f[x]);
}
int main() {
#ifndef ONLINE_JUDGE
    FIN
#endif
    cin>>n>>m;
    int minn=0;
    a[0]=INF;
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        if(a[i]<a[minn]) minn=i;
    }
    for(int i=1;i<=n;i++){
        edge[i]=(EDGE){i,minn,a[i]+a[minn]};
        f[i]=i;
    }
    for(int i=n+1;i<=n+m;i++){
        scanf("%d%d%lld",&edge[i].u,&edge[i].v,&edge[i].w);
    }
    sort(edge+1,edge+1+n+m);
    LL ans=0;
    for(int i=1;i<=n+m;i++){
        int u=find(edge[i].u);
        int v=find(edge[i].v);
        if(u!=v){
            f[u]=v;
            ans+=edge[i].w;
        }
    }
    cout<<ans<<endl;
}