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

Codeforces Round #529 (Div. 3)

A - Repeating Cipher

我做的好慢啊。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cmath>
#include<cctype>
using namespace std;

typedef long long ll;
const int Maxn=410000;

int n;
char s[Maxn],a[Maxn];

int main() {
    scanf("%d",&n);
    scanf("%s",s);
    int temp=0;
    while(temp*(temp+1)/2<n) temp++;
    for(int i=temp;i>=1;i--)
        a[i-1]=s[i*(i+1)/2-1];
    printf("%s\n",a);
    return 0;
}

B - Array Stabilization

刪掉的肯定是最大或最小,那麼記下來最大,次大,最小,次小,然後就可以輸出了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cmath>
#include<cctype>
using namespace std;

typedef long long ll;
const int Maxn=410000;

int n,x;

int main() {
    scanf("%d",&n);
    int zd=0,cd=0,zx=0x7fffffff,cx=zx;
    while(n--) {
        scanf("%d",&x);
        if(x>zd) {
            cd=zd;zd=x;
        }
        else cd=max(cd,x);
        if(x<zx) {
            cx=zx;zx=x;
        }
        else cx=min(cx,x);
    }
    printf("%d\n",min(cd-zx,zd-cx));
    return 0;
}

C - Powers Of Two

首先把n分解一下,如果k比n大,顯然無解,如果k個數組成不了n,顯然無解,然後每次把一個二的冪拆成兩個,如果拆成了1就特判一下,然後輸出即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cmath>
#include<cctype>
using namespace std;

typedef long long ll;
const int Maxn=410000;

int n,k,a[Maxn],tot,cnt;

int main() {
    scanf("%d%d",&n,&k);
    if(n<k) {
        puts("NO");
        return 0;
    }
    int temp=1;
    while(n) {
        if(n&1) a[++tot]=temp;
        temp<<=1,n>>=1;
    }
    if(tot>k) {
        puts("NO");
        return 0;
    }
    k-=tot;
    while(k) {
        int temp=a[tot];
        tot--;
        if(temp==1)
            cnt++;
        else {
            temp>>=1;
            a[++tot]=temp;
            a[++tot]=temp;
            k--;
        }
    }
    puts("YES");
    for(int i=1;i<=cnt;i++) printf("1 ");
    for(int i=1;i<=tot;i++) printf("%d ",a[i]);
    return 0;
}

D - Circular Dance

首先如果n==3,那麼就隨便輸出,否則的話,因為每個人都記下來了下面的兩個人,所以就能判斷出來哪個和他緊挨著,然後就能求出來了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cmath>
#include<cctype>
using namespace std;

typedef long long ll;
const int Maxn=410000;

int n,x[Maxn],y[Maxn],nxt[Maxn];

int main() {
    scanf("%d",&n);
    if(n==3) {
        puts("1 2 3");
        return 0;
    }
    for(int i=1;i<=n;i++)
        scanf("%d%d",&x[i],&y[i]);
    int temp=1,tempp;
    if(x[x[1]]==y[1]||y[x[1]]==y[1]) tempp=x[1];
    else tempp=y[1];
    nxt[temp]=tempp;
    while(tempp!=1) {
        int sxz;
        if(x[temp]==tempp) sxz=y[temp];
        else sxz=x[temp];
        temp=tempp;tempp=sxz;
        nxt[temp]=tempp;
    }
    int now=nxt[1];printf("1 ");
    while(now!=1) {
        printf("%d ",now);
        now=nxt[now];
    }
    return 0;
}

E - Almost Regular Bracket Sequence

首先肯定是把左括號換成1,右括號換成-1,求一下和。因為變了一個括號,那麼總和變化值一定是2或-2,那麼如果總和不是2或-2,一定無解。

如果總和是-2,那麼一定是一個右括號變成了左括號,那麼我們就把所有的右括號變成左括號,左括號變成右括號,然後把序列倒過來,就可以變成總和為2的情況。

然後我們考慮一下總和為2的情況怎麼做。首先還是從左到右掃,考慮一下如果把一個左括號變成右括號,那麼會使得現在的總和-2。所以我們記下來字首總和和字首左括號數,如果字首總和小於0,那麼就無解,然後因為在這個位置左邊把一個左括號變成右括號,勢必會使這個位置的和-2,那麼如果這個位置的和小於2,在這個位置左邊都沒有解,就把字首左括號數清零即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cctype>
using namespace std;

char gc() {
//  static char buf[100000],*p1,*p2;
//  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    return getchar();
}

template<class T>
int read(T& ans) {
    ans=0;T f=1;
    char ch=gc();
    while(!isdigit(ch)) { if(ch=='-') f=-1; if(ch==EOF) return -1; ch=gc(); }
    while(isdigit(ch)) ans=ans*10+ch-'0',ch=gc();
    ans*=f;
    return 1;
}

typedef long long ll;
const int Maxn=2100000;
const int inf=0x3f3f3f3f;

int n,a[Maxn],sum,ans;
char s[Maxn];

int main() {
//  freopen("test.in","r",stdin);
    scanf("%d%s",&n,s+1);
    for(int i=1;i<=n;i++) a[i]=s[i]=='('?1:-1;
    for(int i=1;i<=n;i++) sum+=a[i];
    if(sum!=2&&sum!=-2) return 0*puts("0");
    if(sum==-2) {
        for(int i=1;i<=n;i++) a[i]*=-1;
        for(int l=1,r=n;l<r;l++,r--) swap(a[l],a[r]);
    }sum=0;
    for(int i=1;i<=n;i++) {
        sum+=a[i];if(a[i]>0) ans++;
        if(sum<2) ans=0;
        if(sum<0) return 0*puts("0");
    }
    printf("%d\n",ans);
    return 0;
}

F - Make It Connected

首先我們可以發現,最終答案上的邊,要麼是題目中給定的,要麼就是向權值最小的點連邊。因為假設答案中有一條邊\((u,v)\)不是題目給定的邊,那麼邊權即為\(a_u+a_v\),設權值最小的點為x,因為u和v最終還是要和x所在的聯通塊連邊,那麼我們假設是v向該聯通塊連邊,那麼u可以向x連邊,因為\(a_x\le a_v\),所以向x連邊一定不會比向v連邊更劣。

那麼我們就把所有邊以及所有點連向x的邊做最小生成樹即可。

#include<cstdio>
#include<algorithm>
using namespace std;

typedef long long ll;

const int Maxn=1100000;

struct node {
    int x,y;
    ll w;
    node(int u=0,int v=0,ll wi=0) {
        x=u;y=v;w=wi;
    }
}a[Maxn];

int n,m,f[Maxn];
ll b[Maxn];

int cmp(node a,node b) {
    return a.w<b.w;
}

int find(int x) {
    if(x!=f[x]) f[x]=find(f[x]);
    return f[x];
}

int main() {
    scanf("%d%d",&n,&m);
    ll temp=0x7fffffffffffffff,ans=0;
    int zhy;
    for(int i=1;i<=n;i++) {
        scanf("%I64d",&b[i]);
        if(b[i]<temp) {
            zhy=i;
            temp=b[i];
        }
        f[i]=i;
    }
    for(int i=1;i<=m;i++)
        scanf("%d%d%I64d",&a[i].x,&a[i].y,&a[i].w);
    for(int i=1;i<=n;i++) a[++m]=node(i,zhy,temp+b[i]);
    sort(a+1,a+m+1,cmp);
    for(int i=1;i<=m;i++)
        if(find(a[i].x)!=find(a[i].y))
            f[f[a[i].x]]=f[a[i].y],ans+=a[i].w;
    printf("%I64d\n",ans);
    return 0;
}