Codeforces #303 Div 2 簡要題解

比賽總結

第一次AK掉div 2,非常開心,罰時也還好。
比賽中的提交記錄
這裏寫圖片描述
在正式和非正式選手中排名179名(共6932人)
這裏寫圖片描述

在正式選手裏排名27名(共2826人)

A. Toy Cars

題目鏈接

http://codeforces.com/contest/545/problem/A

題目大意

給出每個車i 和其他車j 的碰撞情況(i 撞毀、j 撞毀、ij 均撞毀、ij 均未撞毀),問有多少個車在和其他任意車碰撞後,都不會撞毀

思路

水題,就不多說了

代碼

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>

#define MAXN 110

using namespace std;

int mat[MAXN][MAXN],n;
int sol[MAXN],top=0;

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            scanf("%d",&mat[i][j]);
    for(int i=1;i<=n;i++)
    {
        bool flag=true;
        for(int j=1;j<=n;j++)
            if(mat[i][j]==1||mat[i][j]==3)
        {
            flag=false;
            break;
        }
        if(flag) sol[++top]=i;
    }
    printf("%d\n",top);
    if(!top) return 0;
    for(int i=1;i<=top;i++)
        printf("%d ",sol[i]);
    printf("\n");
    return 0;
}

B. Equidistant String

題目鏈接

http://codeforces.com/contest/545/problem/B

題目大意

定義兩個串ST 的差別度diff(S,T) 爲,STSiTii 的個數
要你構造一個串A ,使得diff(A,S)=diff(A,T)

思路

水題,首先看ST 有多少位不相同,若不相同的位的個數tot 爲奇數則顯然無解,否則構造一個串A ,其中若Si=Ti ,則Ai=Si ,前tot2SiTi 的位置填Si ,後tot2SiTi 的位置填Ti

代碼

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>

#define MAXN 110000

using namespace std;

char A[MAXN],B[MAXN];
int n;

int main()
{
    scanf("%s",A+1);
    scanf("%s",B+1);
    n=strlen(A+1);
    int tot=0;
    for(int i=1;i<=n;i++)
        if(A[i]!=B[i])
            tot++;
    if(tot&1)
    {
        printf("impossible\n");
        return 0;
    }
    tot/=2;
    for(int i=1,t=1;i<=n;i++)
    {
        if(A[i]==B[i]) printf("%c",A[i]);
        else if(t<=tot) {printf("%c",A[i]); t++;}
        else printf("%c",B[i]);
    }
    printf("\n");
    return 0;
}

C. Woodcutters

題目鏈接

http://codeforces.com/contest/545/problem/C

題目大意

一共有n 個樹,你要從第一個樹一直砍到最後一個樹。對於每個高度爲hi 、樹根在xi 的樹,你可以選擇拔除它,留下區間爲[xi,xi] 的坑,或者讓它往左邊倒,留下區間爲[xihi,xi] 的坑,或者讓它往右邊倒,留下區間爲[xi,xi+hi] 的坑,但是砍樹的前提是,留下的新坑不能和以前任何一個老坑相交,問最多能讓多少個樹倒下而不是拔除

思路

i 個樹能否倒下,取決於第i1 個樹的狀態,因此我們可以做O(n) 的DP。用f[i][0] 表示第i 個樹往左倒,最多能倒下的樹的個數,用f[i][1] 表示第i 個樹拔除掉,最多能倒下的樹的個數,用f[i][2] 表示第i 個樹往右倒,最多能倒下的樹的個數

然後剩餘要做的事就是各種特判了。

代碼

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>

#define MAXN 110000

using namespace std;

typedef long long int LL;

int n;
LL h[MAXN],x[MAXN];
int f[MAXN][3];

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%I64d%I64d",&x[i],&h[i]);
    f[1][0]=f[1][1]=f[1][2]=1;
    for(int i=2;i<=n;i++)
    {
        //往左倒
        if(x[i]-h[i]>x[i-1]+h[i-1]) f[i][0]=max(f[i][0],f[i-1][2]+1);
        if(x[i]-h[i]>x[i-1])
        {
            f[i][0]=max(f[i][0],f[i-1][1]);
            f[i][0]=max(f[i][0],f[i-1][0]+1);
        }
        //拔出
        if(x[i]>x[i-1]) f[i][1]=max(f[i][1],f[i-1][1]);
        if(x[i]>x[i-1]+h[i-1]) f[i][1]=max(f[i][1],f[i-1][2]+1);
        if(x[i]>x[i-1]) f[i][1]=max(f[i][1],f[i-1][0]+1);
        //往右倒
        if(x[i]>x[i-1]+h[i-1]) f[i][2]=max(f[i][2],f[i-1][2]+1);
        if(x[i]>x[i-1])
        {
            f[i][2]=max(f[i][2],f[i-1][1]);
            f[i][2]=max(f[i][2],f[i-1][0]+1);
        }
    }
    printf("%d\n",max(max(f[n][0],f[n][1]),f[n][2]));
    return 0;
}

D. Queue

題目鏈接

http://codeforces.com/contest/545/problem/D

題目大意

給你n 個人,每個人要去銀行窗口花ti 的時間辦事,每個人的等待時間是其在隊列裏前面的人的ti 之和。一個人如果其ti 大於等於其等待時間的話,他就高興,否則不高興。問排列整個隊列後,最多能讓多少個人高興。

思路

非常水的DP,顯然要讓ti 儘量小的人儘量放在隊列的前面。因此我們可以首先對ti 進行排序,然後維護當前的等待時間(ti 前綴和),依次將ti 從小到大放入隊列裏,並更新高興的人的個數。但是需要注意,如果當前的ti 比當前的等待時間小的話,那麼現在無論如何都無法滿足這個人的需求了,就需要把這個人放到隊列的最末端,這樣的話,就不會耽誤他後面的人的等待時間了,還可以多滿足一些後面的人。剛開始我就因爲這個問題wa了一發。

代碼

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <queue>

#define MAXN 110000

using namespace std;

typedef long long int LL;

//priority_queue<LL>heap;
int n;
LL t[MAXN];

int main()
{
    int ans=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%I64d",&t[i]);
    sort(t+1,t+n+1);
    //reverse(t+1,t+n+1);
    LL nowt=0;
    for(int i=1;i<=n;i++)
    {
        if(t[i]<nowt) continue;
        ans++;
        nowt+=t[i];
    }
    printf("%d\n",ans);
    return 0;
}

E. Paths and Trees

題目鏈接

http://codeforces.com/contest/545/problem/E

題目大意

給你一個無向圖,要你找出一個生成樹,使得生成樹裏S 到其他任何點的最短路和原圖裏S 到其他任何點的最短路長度一樣。找出滿足這樣的條件的最小的生成樹。

思路

首先,kruscal的做法顯然是錯誤的,具體可以看第二個樣例。

我們不妨用單源最短路算法先求出一個從S 出發的最短路樹,顯然這樣的樹是滿足要求的。但是還不能滿足這個生成樹最小的要求。

不妨改進堆優化Dijsktra。堆中不僅記錄點和點到S的距離,還要加上一個標記:這個點是從哪條邊走過來的。這樣的話,假如在做dijsktra時,我們同時看到有兩個點到S 的最短路相同,我們就可以優先把前驅邊權較小的那個點加入最短路樹。

代碼

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <queue>

#define MAXN 610000

using namespace std;

typedef long long int LL;

struct edge
{
    int u,v,id,next;
    LL w;
}edges[MAXN];

int n,m;

int head[MAXN],nCount=1;

void AddEdge(int U,int V,LL W,int ID)
{
    edges[++nCount].u=U;
    edges[nCount].v=V;
    edges[nCount].w=W;
    edges[nCount].id=ID;
    edges[nCount].next=head[U];
    head[U]=nCount;
}

LL dist[MAXN];
bool vis[MAXN];
bool used[MAXN];
int pre[MAXN];

struct Info
{
    int u;
    LL w;
    LL dis;
    Info(int _u,LL _d,LL _w):u(_u),dis(_d),w(_w){}
};

bool operator<(Info a,Info b)
{
    if(a.dis==b.dis) return a.w<b.w;
    return a.dis<b.dis;
}

bool operator>(Info a,Info b)
{
    if(a.dis==b.dis) return a.w>b.w;
    return a.dis>b.dis;
}

priority_queue<Info,vector<Info>,greater<Info> >heap;

void heapdij(int S)
{
    memset(dist,0x3f,sizeof(dist));
    dist[S]=0;
    heap.push(Info(S,0,0));
    while(!heap.empty())
    {
        Info now=heap.top();
        heap.pop();
        int u=now.u;
        if(vis[u]) continue;
        vis[u]=true;
        for(int p=head[u];p!=-1;p=edges[p].next)
        {
            int v=edges[p].v;
            if(dist[u]+edges[p].w<=dist[v])
            {
                if(pre[v]!=-1) used[pre[v]]=false;
                pre[v]=edges[p].id;
                used[edges[p].id]=true;
                dist[v]=dist[u]+edges[p].w;
                heap.push(Info(v,dist[v],edges[p].w));
            }
        }
    }
}

int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int u,v;
        LL w;
        scanf("%d%d%I64d",&u,&v,&w);
        AddEdge(u,v,w,i);
        AddEdge(v,u,w,i);
    }
    int S;
    scanf("%d",&S);
    heapdij(S);
    LL tot=0;
    for(int i=1;i<=m;i++)
        if(used[i]) tot+=(LL)edges[i*2].w;
    printf("%I64d\n",tot);
    for(int i=1;i<=m;i++)
        if(used[i])
            printf("%d ",i);
    printf("\n");
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章