2018 ACM-ICPC World Finals - Beijing

2018 ACM-ICPC World Finals - Beijing


A. Catch the Plane

\(dp[v_i,t_i]\)表示時刻\(t_i\)\(v_i\)點,到達終點的最大機率,那麼轉移方程爲:
\(dp[(v_i,t_i)] = max(P_{ij}*dp[(v_{j+1},t_{j+1})] + (1-Pij)*dp[(v_{i+1},t_{i+1})])\)
\(dp[(v_i,t_i)] = max(dp[v_{i+1},t_{i+1}])\)
其中\((v_i,t_i)\)的一個後繼狀態爲\((v_j,t_j)\)兩個狀態之間的轉移機率爲\(P_{ij}\),第一種轉移:沿\(P_{ij}\)這個方向轉移,以及繼續留在這個點等待下次轉移(\((v_{i+1},t_{i+1})\)爲同一位置下與\(t_i\)最接近的下一個時間);第二種轉移是:直接選擇繼續等待的機率。想出這些後,覺得能夠愉快的ac了。然而調到早上7點。。。才弄好html

  • 問題一:%I64d讀1e18,蜜汁爆了,換了幾個編譯器才發現。。。
  • 問題二:爲簡化代碼省略了討論,致使後面一個點wa
  • 問題三:起點和終點要單獨加進去,致使後面一個點wa
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
typedef long double LD;
typedef unsigned long long ll;
const int N = 5e6 + 100;
using namespace std;
struct node {
    int x; ll t;
    node(){}node(int a,ll b) {x=a,t=b;}
    bool operator < (const node a) const {
        if(t==a.t) return  x<a.x;
        return t < a.t;
    }
};
bool cmp(node a,node b) {
    if(a.x==b.x) return a.t < b.t;
    return a.x < b.x;
}
bool cmp0(node a,node b) {
    if(a.t==b.t) return a.x > b.x;
    return a.t < b.t;
}
vector<node> v;
map<node,int> id;
node fid[N];
int cnt;

int nxt[N];
LD dp[N];
vector< pair<int,LD> > E[N];
void nwnode(node a) {
    if(id[a]!=0) return;
    ++cnt;
    fid[cnt] = a;
    id[a] = cnt;
}
void add(int a,int b,LD p){
    E[a].pb(make_pair(b,p));
}
int n,m;
ll k;

int main() {int f=0;
    ll MX=0,MN=1000000000000000002LL;
    scanf("%d%d%llu",&m,&n,&k);
    rep(i,1,m) {int a,b;ll s,t; double p;
        scanf("%d %d %llu %llu %lf",&a,&b,&s,&t,&p);
        if(t<=k){
            nwnode(node(a,s));
            nwnode(node(b,t));

            add(id[node(a,s)],id[node(b,t)],(LD)p);
            v.pb(node(a,s));
            v.pb(node(b,t));
            if(b == 1LL) {
                dp[id[node(b,t)]] = 1.0;
                MX = max(t,MX);
            }
            if(a==0){
                if(!f)MN=t;
                else MN=min(MN,t);
                f=1;
            }
        }
    }

    nwnode(node(1,MX));
    nwnode(node(1,k));
    nxt[id[node(1,MX)]] = id[node(1,k)];
    dp[id[node(1,k)]] = 1.0;
    v.pb(node(1,k));
    add(id[node(1,MX)],id[node(1,k)],1.0);

    nwnode(node(0,0));
    v.pb(node(0,0));
    nxt[id[node(0,0)]] = id[node(0,MN)];
    add(id[node(0,0)],id[node(0,MN)],1.0);

    sort(v.begin(),v.end(),cmp);
    for(int i=v.size()-2;i>=0;--i) {
        if(v[i].x==v[i+1].x){
            if(v[i].t == v[i+1].t) nxt[id[v[i]]] = nxt[id[v[i+1]]];
            else nxt[id[v[i]]] = id[v[i+1]];
        }
    }
    sort(v.begin(),v.end(),cmp0);

    for(int i=v.size()-1;i>=0;--i) if(dp[id[v[i]]]==0){
        LD mx = 0;int t = id[v[i]];
        for(int j=0;j<E[t].size();++j) {
            if(fid[nxt[E[t][j].first]].x == fid[E[t][j].first].x && fid[nxt[t]].x == fid[t].x && dp[nxt[t]]!=0 && dp[nxt[E[t][j].first]]!=0 )
                mx = max(mx, E[t][j].second*dp[nxt[E[t][j].first]] + (1.0-E[t][j].second)*dp[nxt[t]]);
            else if(fid[nxt[E[t][j].first]].x == fid[E[t][j].first].x && dp[nxt[E[t][j].first]]!=0)
                mx = max(mx, E[t][j].second*dp[nxt[E[t][j].first]]);
            else if(fid[nxt[t]].x == fid[t].x && dp[nxt[t]]!=0)
                mx = max(mx, (1.0-E[t][j].second)*dp[nxt[t]]);
        }
        if(fid[nxt[t]].x == fid[t].x)
            mx = max(mx, dp[nxt[t]]);
        dp[t] = mx;
    }
    printf("%.10f\n",(double)dp[id[node(0,0)]]);
    return 0;
}

B. Comma Sprinkler

這題沒什麼難度,把單詞取出來直接搜索便可。node

#include <bits/stdc++.h>
#define pb push_back
typedef long long ll;
const int N = 1000100;
using namespace std;
string s, word[N];
int cnt;
void chai(string s) {
    int n = s.size();
    cnt = 1;
    for(int i=0;i<n;++i) {
        if(s[i]==' '){
            word[cnt] += ' ';
            ++cnt;
        }
        else
            word[cnt]+=s[i];
    }
}
map< string,vector<string> > pre,last;
string delco(string s) {
    string t;t.clear();
    for(auto c: s) if(c>='a'&&c<='z') t+=c;
    return t;
}
int iscolst(string s) {
    int t = s.size()-1;
    while(t>=0){
        if(s[t]==',')return 1;
        --t;
    }
    return 0;
}
int isbiaolst(string s) {
    int t = s.size()-1;
    while(t>=0){
        if(s[t]=='.'||s[t]==',')return 1;
        --t;
    }
    return 0;
}
map<string,bool> vispre,vislst;
void X(string s);
void Y(string s);
void X(string s) {
    vislst[s] = 1;
    for(int x=0;x<last[s].size();++x) if(!vispre[last[s][x]]) Y(last[s][x]);
}
void Y(string s) {
    vispre[s] = 1;
    for(int x=0;x<pre[s].size();++x) if(!vislst[pre[s][x]]) X(pre[s][x]);
}
string update(string s) {
    s+=',';
    int t=s.size()-1;
    swap(s[t],s[t-1]);
    return s;
}
int main() {
    getline(cin,s); chai(s);
    for(int i=2;i<=cnt;++i) if(!isbiaolst(word[i-1])){
        pre[delco(word[i])].pb(delco(word[i-1]));
    }
    for(int i=1;i<cnt;++i) if(!isbiaolst(word[i])){
        last[delco(word[i])].pb(delco(word[i+1]));
    }
    for(int i=1;i<cnt;++i) {
        string t = delco(word[i]);
        if(!vislst[t]&&iscolst(word[i]))X(t);
    }
    for(int i=2;i<=cnt;++i) {
        string t=delco(word[i]);
        if(!vispre[t]&&iscolst(word[i-1])) Y(t);
    }
    for(int i=1;i<=cnt;++i) {
        string t = delco(word[i]);
        if(vislst[t]&&!isbiaolst(word[i]))
            cout << update(word[i]);
        else
            cout << word[i];
    }puts("");
    return 0;
}

F. Go with the Flow

把單詞的長度記錄下來,模擬放單詞,把全部位置上是空格的位置按從上到下存起來。順序dp求出每一個位置向上最長走多遠,dp過程當中取最大值便可,這樣複雜度與空格數成正比,看大佬代碼學習了一下,巧妙地解決了dp數組的開法用一維存,這樣空間就不隨着寬度變化。一開始寫的暴力bfs炸的妥妥的。c++

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define PII pair<int,int>
#define MP make_pair
#define fr first
#define sc second
typedef long long ll;
const int N = 5600;
using namespace std;
int n,L[N],len;
char s[88];
PII A[N];
int cnt,f[N*188];

void cal_A(int w) {
    int x=1,y=0;cnt=0;
    rep(j,1,n) {
        if(y+L[j]<=w){
            if(y)A[++cnt]=MP(x,y);
            y+=L[j]+1;
        }
        else {
            ++x;
            y=L[j]+1;
        }
    }
}
int cal_id(int x,int y,int m) {
    if(x<1)return 0;
    if(y<1||y>m)return 0;
    return (x-1)*m + y;
}
int main() {
    int MX = 0;
    scanf("%d",&n);
    for(int i=1;i<=n;++i) {
        scanf(" %s",s);
        L[i]=strlen(s);
        MX = max(MX,L[i]);
        len += L[i];
    }
    len += (n-1);

    int ans=0,ans1=0,tmp;
    rep(i,MX,len) {
        cal_A(i);tmp = 0;

        rep(j,1,cnt){
            int x=A[j].fr, y=A[j].sc;
            f[cal_id(x,y,i)] = max(f[cal_id(x-1,y-1,i)],f[cal_id(x,y,i)]);
            f[cal_id(x,y,i)] = max(f[cal_id(x-1,y,i)],f[cal_id(x,y,i)]);
            f[cal_id(x,y,i)] = max(f[cal_id(x-1,y+1,i)],f[cal_id(x,y,i)]);
            ++f[cal_id(x,y,i)];
            tmp = max(tmp,f[cal_id(x,y,i)]);
        }
        if(tmp>ans){
            ans=tmp;
            ans1=i;
        }
        rep(j,1,cnt)f[cal_id(A[j].fr,A[j].sc,i)]=0;
    }
    printf("%d %d\n",ans1,ans);
    return 0;
}

K. Wireless is the New Fiber

貪心,首先答案是一棵樹,既有n-1條邊,因此要減小的總邊數固定,因此咱們儘可能要改變度數大的點,換一句話必定先知足分叉少的。如今考慮如何知足,注意到度數爲1的點是很特殊的,咱們必定要先知足他們,而且最好他們不互相鏈接,那就把他們接在其餘度數較小的點上,顯然最好不接滿。咱們已經肯定,若是有度爲1的點,必定要先知足它,那麼考慮如何把度非1的點轉換爲度爲1的點,顯然就是把度數爲1的點接上去使他剛好多餘一個位置,這些點組成的集合即是一個新的度爲1的點,如此反覆到沒法產生新的度爲1的點集。接下來咱們仍然優先知足度數小的點,先把全部的1接上去,剩下的位置怎麼辦,我用度數最大的點接上去,把他們看成度數爲1的點,爲何?由於這些點的度數最大,能夠儘量的把減小的邊用在他們身上,重複上述操做,直到不足以產生新的度數爲1的點集。最後把剩餘的點所有加到當前節點上。若是最終有多個的度數爲1的點集,那把他們任意連成一棵樹樹便可。這題的貪心,我以前一直在胡寫,也沒證實出來作法的正確性。。GG。。。。膜了大佬的寫法數組

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define pb push_back
typedef long long ll;
const int N = 10000 + 10;
using namespace std;
int n,m,d[N];
vector<int> G[N];
void add(int u,int v) {G[u].pb(v);}
struct node {
    int id,d;
    node(){}node(int a,int b){id=a,d=b;}
}a[N];
int b[N];
int cnt,cnt0;
bool cmp(node a,node b) {return a.d < b.d;}
vector<int> v;
int main() {
    scanf("%d%d",&n,&m);
    rep(i,1,m) {int x,y;
        scanf("%d%d",&x,&y);
        ++d[x],++d[y];
    }

    for(int i=0;i<n;++i) a[cnt++] = node(i,d[i]);
    sort(a,a+cnt,cmp);

    for(int i=0;i<cnt;++i) {
        if(a[i].d==1) v.push_back(a[i].id);
        else if(v.size() >= a[i].d-1){
            for(int j=0;j<a[i].d-1;++j) {
                add(a[i].id,v[v.size()-1]);
                v.pop_back();
            }
            v.push_back(a[i].id);
        }
        else if(v.size()+cnt-i-1>=a[i].d-1){
            for(int j=0;j<v.size();++j) {
                add(v[j],a[i].id);
            }
            for(int j=0;j<a[i].d-1-v.size();++j){
                add(a[i].id,a[--cnt].id);
            }
            v.clear();
            v.push_back(a[i].id);
        }
        else {
            for(int j=0;j<v.size();++j){
                add(a[i].id,v[j]);
            }
            for(int j=i+1;j<cnt;++j){
                add(a[i].id,a[j].id);
            }
            v.clear();
            break;
        }
    }
    if(v.size()>0){
        for(int i=1;i<v.size();++i){
            add(v[0],v[i]);
        }
    }


    for(int i=0;i<n;++i){
        for(int j=0;j<G[i].size();++j) {
            --d[i],--d[G[i][j]];
        }
    }
    int num=0;
    rep(i,0,n-1)if(d[i])++num;
    printf("%d\n",num);
    printf("%d %d\n",n,n-1);
    rep(i,0,n-1){
        rep(j,0,(int)G[i].size()-1) {
            printf("%d %d\n",i,G[i][j]);
        }
    }

    return 0;
}
相關文章
相關標籤/搜索