2016年8月29日 星期一

(Codeforces) 623B. Array GCD

http://codeforces.com/problemset/problem/623/B

solution : http://codeforces.com/contest/623/submission/20172218

題目大意:給你一個長度n的序列(1<=n<=10^6),裡面的每個值ai的範圍在[2,10^9]。現在,你可以做兩件事情:(1)刪除掉這個序列的 某個子序列(長度<=n-1) 這會花費a * m元,其中m是子序列的長度 (2)把序列的任意值 +1 or -1,把做一次這個動作,會花費b元。在你經過這兩件事情後,你會得到一個新的序列。題目的要求是:使得這個新序列的gcd值 >= 2。

可以注意到的一件事情是說:這個序列一定會包含 a1-1,a1,a1+1, an-1,an,an+1 的其中一個值(也就是說,開頭or尾巴 一定有一個可以留下來!)。因此,我們可以dp。一旦上面那六個值中的其中一個選定了,所擁有的質數有確定了!

假設我們擁有的質數是p,我們開三條dp陣列(dp[3][n]),其中dp[0][i]是指一路來在只有做     操作2 的情況下,前i個的最小cost,若無此case,則為INF。dp[1][i]是指在第i個把挖掉的情況下,前i個的最小cost。dp[2]則為在i之前已經刪除一段序列的情況下,前i個的最小值,若無此case,則為INF。 

我們先定義 "合法" : 在經過操作後,得到的數字 % p == 0,其中p是上述中,選定的質數。

那麼,我們可以得到以下結論:

dp[0][i] = (如果合法)dp[0][i-1]+費用(沒有做操作2,就是0,其他情況就是b)
dp[1][i] = min( dp[0][i-1] + a, dp[1][i-1] + a)
dp[2][i] = min( (如果合法)dp[0][i-1] + 費用, dp[2][i-1] + 費用  )

如果有看不懂的話,歡迎在下面留言喔~




2016年8月26日 星期五

(Codeforces) 623A. Graph and String

http://codeforces.com/problemset/problem/623/A

solution : http://codeforces.com/contest/623/submission/20080880

題目大意:有一個人,他先寫下一個長度n(1<=n<=500)的字串,裡面只包含'a' , 'b' , 'c'。接下來,他把字串中的每個字元視為一個節點,字元符合下面的情況時,會建邊:'a' - 'a' , 'b' - 'b' , 'c' - 'c' , 'a' - 'b' , 'b' - 'c' (也就是說,只要兩個點相等時 or 字母表的相鄰兩個點) 。畫完圖後,他就把字串給擦掉了。 隔天,他的朋友看到這張圖,他的朋友希望她能看到原本的字串。 請你給出任意一組合法解。

可以先注意到的兩個特性:(1) 'b'可以與任意相接 (2) 'a' - 'c'不相連。

接下來,我們就尋找每個不相連的邊,一個設定成'a',另外一個設定成'c',其他如果不相關的通通設定成'b'。如果在過程中,發現有矛盾的情況,那就是不可能發生。

2016年8月25日 星期四

Educational Codeforces Round 16

http://codeforces.com/contest/710

想說剛進div.1 ,先打場Educational Round試試手感。結果16min之後就沒再傳code了...

Problems :
pA : http://codeforces.com/contest/710/problem/A
pB : http://codeforces.com/contest/710/problem/B
pC : http://codeforces.com/contest/710/problem/C
pD : http://codeforces.com/contest/710/problem/D
pE : http://codeforces.com/contest/710/problem/E
pF : http://codeforces.com/contest/710/problem/F

My solutions :
pA : http://codeforces.com/contest/710/submission/20047572
pB : http://codeforces.com/contest/710/submission/20048663
pC : http://codeforces.com/contest/710/submission/20051573
pE : http://codeforces.com/contest/710/submission/20142269

題解:

pA :
題目大意:給你一個在西洋棋盤上面的格子,請輸出如果那個格子擺的是King(國王),他可以走幾步。

基本上可以分三種case : 四個角,邊,中間。判斷方法可以用第一個是'a', 'h'或第二個是 '1','8'等判斷,詳細可以參考我的code。

pB :
題目大意:一個長度n的a序列(1<=n<=3*10^5),請找出最小的點x,使得|a1-x|+|a2-x| + ... + |an-x|有最小值,如果x有很多解,請輸出最左邊的。

這個比較算是數學解:把a排序,然後輸出中間的點即可。這個算是絕對值圖形的特性。

pC :
題目大意:給你一個奇數n(1<=n<=49),請製造出一個n*n的矩陣,使得每一行、列、斜邊的和都是奇數。

Jury的解法大概是圖片(一)的樣子,我的解法是:讓每個行、列、斜邊的和都一樣。

圖一:

pE :
題目大意:現在你需要作出n個'a' (1<=n<=10^7),其中你可以使用三種操作:再任意處插入、刪除一個'a',這花費了a元、複製貼上目前的字串,這花費'b'元。請求出最小的花費。

這是一題dp題:令dp[i]代表說:有i個'a'的最佳解。則初始化條件為dp[1] = a,遞迴式為:若i%2==0,則dp[i] = max(dp[i-1] + a, dp[i/2] + b) else : dp[i] = max(dp[i-1]+a,max(dp[i/2]+b+a,dp[i/2+1] + b+a)。看code應該會比較清楚XD。









2016年8月22日 星期一

Codeforces Round #368 (Div. 2)

經過了好久,終於晉級Div. 1了~~   Candidate Master 

希望之後能夠維持穩定再Div.1 ~~

http://www.codeforces.com/contest/707

題目:
pA : http://www.codeforces.com/contest/707/problem/A
pB : http://www.codeforces.com/contest/707/problem/B
pC : http://www.codeforces.com/contest/707/problem/C
pD : http://www.codeforces.com/contest/707/problem/D
pE : http://www.codeforces.com/contest/707/problem/E

My solutions :
pA : http://www.codeforces.com/contest/707/submission/19982541
pB : http://www.codeforces.com/contest/707/submission/19986266
pC : http://www.codeforces.com/contest/707/submission/19987375
pD : http://www.codeforces.com/contest/707/submission/20037472

題解:

pA :
題目大意:給你一個有n*m個像素的圖片(1<=n,m<=100),每個像素有六種顏色。只要一張圖片中,沒有C , M , Y,就是黑白照片,其他就是彩色照片。

這題主要要小心的部分是字元處理(很多hack神人都利用了這一點),用scanf的要特別特別特別注意!很容易因為字元就雷掉了。所以我用string XD。

pB :
題目大意:現在有n個城市,m條有權重的邊(1<=n,m<=10^5),這其中有k個城市(0<=k<=n)是補給站。現在,你必須要選擇一個不是補給站的城市i,以及一個補給站城市j,這兩座城市必須要有路徑相連。現在,你要想辦法使得權重和變成最小,請問有沒有辦法?

仔細想想後會發現:要使得權重和最小,那勢必說要使得經過的城市越少。那倒不如說,直接一個i(上述的i)跟j(上述的j)之間用一條邊連接就好------這就是重點。所以,我們只要拜訪所有的邊,就okay囉~~。複雜度:O(E)。

pC :
題目大意:給你一個直角三角形的任意一個邊,請給出另外兩個邊。

那我假設題目給我的是n好了,若n=1,2,那一定不行(最小的直角三邊行三個邊長是 3,4,5),最簡單的方法是說:a^2 + n^2 = b^2 ==> n^2 = b^2 - a^2 ==> n^2 = (a-b)(a+b)。那這個時候,我們就可以解聯立解說:a-b=1, a+b=n*n。若這個時候n是偶數,一直除以二,變成奇數即可。(可是我已經忘記我的code到底是如何神奇的運作了,因為這個在我小學六年級的時候就無意間不小心推出來了,所以就直接用,忘記如何解釋了。對於讀者,感到抱歉。)

pD :
題目大意:維護一個n*m書架(1<=n,m<=1000),q比詢問(1<=q<=10^5),這q比詢問中,有四種動作:1.把書放到(i,j) 2.把書從(i,j)移掉 3. 把橫列i中,有書的變沒書,沒書的變有書 4. 變成操作k的模樣。

這題解題其實可以用DFS實作:可以想像成這個狀態要前往那些狀態,這樣就可以用DFS了。詳細的話,可以參考我的code。

後記:
我發現,我擁有access to tags了 XD。



2016年8月17日 星期三

(UVA) 10731 - Test

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=1672

SCC喔!


#include <iostream>
#include <stdio.h>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAX_N = 30;

vector<int> edg[MAX_N];
vector<int> rev_edg[MAX_N];
bool visit[MAX_N];
bool used[MAX_N];
int stamp[MAX_N];
string scc[MAX_N];

inline int f(char c) {
    return c-'A'+1;
}

inline char ff(int x) {
    return x-1+'A';
}

void dfs_for_stamp(int id,int &cur_stamp) {
    visit[id]=true;
    for (auto i=rev_edg[id].begin();i!=rev_edg[id].end();i++) {
        int tmp=*i;
        if (visit[tmp]==false) dfs_for_stamp(tmp,cur_stamp);
    }
    stamp[cur_stamp++]=id;
}

void dfs_for_scc(int id,int num) {
    visit[id]=true;
    for (auto i=edg[id].begin();i!=edg[id].end();i++) {
        int tmp=*i;
        if(visit[tmp]==false) dfs_for_scc(tmp,num);
    }
    int len=scc[num].size();
    scc[num] += " ";
    scc[num][len] = ff(id);
}

int main (){
//    freopen("output.txt","w",stdout);
    int n;
    int cases=1;
    while (scanf("%d",&n) != EOF) {
        if (!n) break;
        if (cases!=1) puts("");
        cases++;
        for (int x=0;MAX_N>x;x++) {
            edg[x].clear();
            rev_edg[x].clear();
            visit[x]=false;
            used[x]=false;
            scc[x]="";
        }
        for (int x=0;n>x;x++) {
            string i[6];
            for(int y=0;6>y;y++) cin>>i[y];
            int id=0;
            for (id=0;5>id;id++) {
                used[f(i[id][0])]=true;
                if (i[id]==i[5]) break;
            }
            for (int y=0;5>y;y++) {
                used[f(i[y][0])]=true;
                if (y==id) continue;
                edg[f(i[id][0])].push_back(f(i[y][0]));
                rev_edg[f(i[y][0])].push_back(f(i[id][0]));
            }
        }
        int cur_stamp=1;
        for (int x=1;MAX_N>x;x++) {
            if (visit[x]==false &&used[x]==true) dfs_for_stamp(x,cur_stamp);
        }
        for (int x=0;MAX_N>x;x++) {
            visit[x]=false;
        }
        int num=1;
        for (int x=cur_stamp-1;x>=1;x--) {
//            cout<<"x="<<x<<endl;
            if (visit[stamp[x]]==false) {
                dfs_for_scc(stamp[x],num++);
            }
        }
//        for (int x=1;num>x;x++) cout<<scc[x]<<endl;
//        cout<<"num="<<num<<endl;
        for (int x=1;num>x;x++) {
            string tmp[MAX_N];
            int len=scc[x].size();
            for (int y=0;len>y;y++) {
                tmp[y]=" ";
                tmp[y][0]=scc[x][y];
            }
            sort(tmp,tmp+len);
            scc[x]="";
            for (int y=0;len>y;y++) {
                scc[x] += tmp[y];
            }
        }
        sort(scc+1,scc+num);
        for (int x=1;num>x;x++) {
            int len=scc[x].size();
            for (int y=0;len>y;y++) {
                if (y!=0) printf(" ");
                char t=scc[x][y];
                printf("%c",t);
            }
            puts("");
        }
    }
}


(UVA) 247 - Calling Circles

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=183

SCC進化版XD

處理字串那裏比較難啦XD



#include <iostream>
#include <stdio.h>
#include <vector>
#include <map>
#include <cstring>
using namespace std;

const int MAX_N = 30;

vector<int> edg[MAX_N];
vector<int> rev_edg[MAX_N];
vector<int> scc[MAX_N];
bool visit[MAX_N];
int stamp[MAX_N];
map<string,int> mp;
string rev_mp[MAX_N];

void dfs_for_stamp(int id,int &cur_stamp) {
    visit[id]=true;
    for (auto i=rev_edg[id].begin();i!=rev_edg[id].end();i++) {
        int tmp=*i;
        if(visit[tmp]==false) dfs_for_stamp(tmp,cur_stamp);
    }
    stamp[cur_stamp++]=id;
}

void dfs_for_scc(int id,int num) {
    visit[id]=true;
    for (auto i=edg[id].begin();i!=edg[id].end();i++) {
        int tmp=*i;
        if (visit[tmp]==false) dfs_for_scc(tmp,num);
    }
    scc[num].push_back(id);
}

int main () {
    int n,m;
    int cases=1;
    while (cin >> n >> m) {
        if (!n && !m) break;
        mp.clear();
        for (int x=0;n>=x;x++) {
            edg[x].clear();
            rev_edg[x].clear();
            scc[x].clear();
            visit[x]=false;
        }
        int id=1;
        for (int x=0;m>x;x++) {
            string i,j;
            cin >> i >>j;
            if(mp.find(i) == mp.end()) {
                mp[i]=id;
                rev_mp[id++]=i;
            }
            if (mp.find(j) == mp.end()) {
                mp[j]=id;
                rev_mp[id++]=j;
            }
            edg[mp[i]].push_back(mp[j]);
            rev_edg[mp[j]].push_back(mp[i]);
        }
        int cur_stamp=1;
        for (int x=1;n>=x;x++) {
            if (visit[x]==false) {
                dfs_for_stamp(x,cur_stamp);
            }
        }
        for(int x=1;n>=x;x++) {
            visit[x]=false;
        }
        int num=1;
        for (int x=n;x>=1;x--) {
            if (visit[stamp[x]]==false) {
                dfs_for_scc(stamp[x],num++);
            }
        }
        if (cases!=1) cout<<endl;
        cout<<"Calling circles for data set "<<cases++<<":\n";
        for(int x=1;num>x;x++) {
            int len=scc[x].size();
            for (int y=0;len>y;y++) {
                if (y!=0) cout<<", ";
                cout<<rev_mp[scc[x][y]];
            }
            cout<<endl;
        }
    }
}



(UVA) 11838 - Come and Go

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=2938

也是SCC的應用喔,這題也可以當模板題。


#include <iostream>
#include <stdio.h>
#include <vector>
#include <cstring>
using namespace std;

const int MAX_N = 2004;

vector<int> edg[MAX_N];
vector<int> rev_edg[MAX_N];
int stamp[MAX_N];
bool visit[MAX_N];

void dfs_for_stamp(int id,int &cur_depth) {
    visit[id]=true;
    for (auto i=rev_edg[id].begin();i!=rev_edg[id].end();i++) {
        int tmp=*i;
        if (visit[tmp]==false) dfs_for_stamp(tmp,cur_depth);
    }
    stamp[cur_depth++]=id;
}

void dfs_for_scc(int id,int scc) {
    visit[id]=true;
    for (auto i=edg[id].begin();i!=edg[id].end();i++) {
        int tmp=*i;
        if (visit[tmp]==false) dfs_for_scc(tmp,scc);
    }
}

int main () {
    int n,m;
    while (scanf("%d %d",&n,&m) != EOF) {
        if (!n && !m) break;
        for (int x=0;n>=x;x++) {
            edg[x].clear();
            rev_edg[x].clear();
            visit[x]=false;
        }
        for (int x=0;m>x;x++) {
            int i,j,k;
            scanf("%d %d %d",&i,&j,&k);
            if (k==1) {
                edg[i].push_back(j);
                rev_edg[j].push_back(i);
            }
            else {
                edg[i].push_back(j);
                edg[j].push_back(i);
                rev_edg[i].push_back(j);
                rev_edg[j].push_back(i);
            }
        }
        int cur_depth=1;
        for (int x=1;n>=x;x++) {
            if (visit[x]==false) dfs_for_stamp(x,cur_depth);
        }
        for (int x=1;n>=x;x++) {
            visit[x]=false;
        }
        int scc=0;
        for (int x=n;x>=1;x--) {
            if (visit[stamp[x]]==false) dfs_for_scc(stamp[x],scc++);
        }
        if(scc==1) puts("1");
        else puts("0");
    }
}


(UVA) 11504 - Dominos [SCC]

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=2499

SCC 模板!


#include <iostream>
#include <stdio.h>
#include <cstring>
#include <vector>
#include <utility>
#include <algorithm>
using namespace std;

typedef pair<int,int> pii;
const int MAX_N = 1e5 + 6;

vector<int> edg[MAX_N];
vector<int> rev_edg[MAX_N];
int stamp[MAX_N];
int in_scc[MAX_N];
int rudu[MAX_N];
bool visit[MAX_N];

void dfs_for_stamp(int id,int &cur_depth) {
    visit[id]=true;
    for (auto i=rev_edg[id].begin();i!=rev_edg[id].end();i++) {
        int tmp=*i;
        if (visit[tmp]==false) dfs_for_stamp(tmp,cur_depth);
    }
    stamp[cur_depth++]=id;
}

void dfs_for_scc(int id,int scc) {
    visit[id]=true;
    for (auto i=edg[id].begin();i!=edg[id].end();i++) {
        int tmp=*i;
        if (visit[tmp]==false) {
            dfs_for_scc(tmp,scc);
        }
    }
    in_scc[id]=scc;
}

int main () {
//    freopen("input.txt","r",stdin);
//    freopen("output.txt","w",stdout);
    int T;
    scanf("%d",&T);
    while (T--) {
        int n,m;
        scanf("%d %d",&n,&m);
        for (int x=0;n>=x;x++) {
            edg[x].clear();
            rev_edg[x].clear();
            stamp[x]=in_scc[x]=rudu[x]=0;
            visit[x]=false;
        }
        for (int x=0;m>x;x++) {
            int i,j;
            scanf("%d %d",&i,&j);
            edg[i].push_back(j);
            rev_edg[j].push_back(i);
        }
        int cur_depth=1;
        for (int x=1;n>=x;x++) {
            if (visit[x]==false) dfs_for_stamp(x,cur_depth);
        }
        for (int x=1;n>=x;x++) {
            visit[x]=false;
        }
        int scc=1;
        for (int x=n;x>=1;x--) {
            if (visit[stamp[x]]==false) {
                dfs_for_scc(stamp[x],scc++);
            }
        }
        for (int x=1;n>=x;x++) {
            for (auto i=edg[x].begin();i!=edg[x].end();i++) {
                int tmp=*i;
                if (in_scc[x]!=in_scc[tmp]) rudu[in_scc[tmp]]++;
            }
        }
        int ans=0;
        for(int x=1;scc>x;x++) {
            if (rudu[x]==0) ans++;
        }
        printf("%d\n",ans);
    }
}


2016年8月16日 星期二

(UVA) 10765 - Doves and bombs

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=1706

割點的強化XD

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <utility>
using namespace std;

typedef pair<int,int> pii;
const int MAX_N = 10004;

int low[MAX_N];
int depth[MAX_N];
vector<int> edg[MAX_N];
bool visit[MAX_N];
int cut_vertex[MAX_N];
int son[MAX_N];
pii ans[MAX_N];

void dfs(int id,int cur_depth,int parent) {
    low[id]=cur_depth;
    visit[id]=true;
    depth[id]=cur_depth;
    for (auto i=edg[id].begin();i!=edg[id].end();i++) {
        int tmp=*i;
        if (visit[tmp] ==true) {
            if (low[id] > depth[tmp]) {
                low[id] = depth[tmp];
            }
        }
        else {
            son[id]++;
            dfs(tmp,cur_depth+1,id);
            if (low[tmp] < low[id]) low[id]=low[tmp];
            else if (low[tmp] >= cur_depth && id!=parent){
                cut_vertex[id]++;
            }
        }
    }
    if (id==parent) cut_vertex[id]=son[id];
}

int main () {
    int n,m;
    while (scanf("%d %d",&n,&m) != EOF) {
        if (!n && !m) break;
        for (int x=0;n>x;x++) {
            edg[x].clear();
            visit[x]=false;
            cut_vertex[x] = 1;
            son[x]=0;
        }
        int i,j;
        while (scanf("%d %d",&i,&j)) {
            if (i==-1&&j==-1) break;
            edg[i].push_back(j);
            edg[j].push_back(i);
        }
        dfs(0,1,0);
        for (int x=0;n>x;x++) {
            ans[x]=make_pair(cut_vertex[x],-x);
        }
        sort(ans,ans+n);
        for (int x=n-1;x>=n-m;x--) {
            printf("%d %d\n",-ans[x].second,ans[x].first);
        }
        puts("");
    }
}



(UVA) 796 - Critical Links [割邊 bridge]

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=737

裸割邊題,也是一樣用tarjan的low函數,不過這次需要考慮重邊 & 從父親來的節點XD。


#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <utility>
#include <set>
using namespace std;

typedef pair<int,int> pii;
const int MAX_N = 1e5+6; //assume, not given in the input

int low[MAX_N];
int depth[MAX_N];
bool visit[MAX_N];
vector<int> edg[MAX_N];
pii ans[MAX_N];
int ans_no;
set<pii> path;
set<pii> repeat;

void dfs(int id,int cur_depth,int parent) {
    visit[id]=true;
    low[id]=cur_depth;
    depth[id]=cur_depth;
    for (auto i=edg[id].begin();i!=edg[id].end();i++) {
        int tmp=*i;
        if (visit[tmp]==true) {
            if (depth[tmp] < low[id] && tmp!=parent) {
                low[id] = depth[tmp];
            }
            else if (depth[tmp]<low[id] && repeat.find(make_pair(tmp,id))!=repeat.end()) {
                low[id] = depth[tmp];
            }
        }
        else {
            dfs(tmp,cur_depth+1,id);
            if (low[tmp] < low[id]) low[id]=low[tmp];
        }
    }
    if (id!=parent && low[id]>=cur_depth) {
        ans[ans_no++]=make_pair(min(parent,id),max(parent,id));
    }
}

int main () {
    int n;
    while (scanf("%d",&n) != EOF) {
        for (int x=0;n>x;x++) {
            edg[x].clear();
            visit[x]=false;
            ans_no=0;
        }
        ans_no=0;
        for (int x=0;n>x;x++) {
            int i,j;
            scanf("%d (%d)",&i,&j);
            for (int y=0;j>y;y++) {
                int k;
                scanf("%d",&k);
                edg[i].push_back(k);
                edg[k].push_back(i);
            }
        }
        for (int x=0;n>x;x++) {
            if (visit[x]==false) dfs(x,1,x);
        }
        sort(ans,ans+ans_no);
        printf("%d critical links\n",ans_no);
        for (int x=0;ans_no>x;x++) {
            printf("%d - %d\n",ans[x].first,ans[x].second);
        }
        puts("");
    }
}


(UVA) 315 - Network [割點 cut vertex]

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=251

裸割點題:用Tarjan算法 的 low 函數:不經過父節點所能到達的最上面深度!實作就看code吧!這裡不需要考慮重邊的部分,因為是cut vertex,重邊的話回到父節點,其實沒差。


#include <iostream>
#include <stdio.h>
#include <cstring>
#include <vector>
using namespace std;

const int MAX_N = 103;

int low[MAX_N];
int depth[MAX_N];
vector<int> edg[MAX_N];
bool visit[MAX_N];
int cut_vertex[MAX_N];
int son[MAX_N];

void dfs(int id,int cur_depth,int parent) {
    visit[id]=true;
    depth[id]=cur_depth;
    low[id]=cur_depth;
    for (auto i=edg[id].begin();i!=edg[id].end();i++) {
        int tmp=*i;
        if (visit[tmp]==true) {
            if (depth[tmp]<low[id] && tmp!=parent) low[id]=depth[tmp];
        }
        else {
            son[id]++;
            dfs(tmp,cur_depth+1,id);
            if (low[tmp] < low[id]) low[id]=low[tmp];
            else if (low[tmp] >= cur_depth && id!=1) cut_vertex[id]=1;
        }
    }
    if (id==1 && son[1]>1) cut_vertex[1]=1;
}

int main (){
//    freopen("output.txt","w",stdout);
    int n;
    while (scanf("%d",&n) != EOF) {
        if (!n) break;
        for (int x=0;n>=x;x++) {
            visit[x]=false;
            edg[x].clear();
            cut_vertex[x]=0;
            son[x]=0;
        }
        int p;
        while (scanf("%d",&p)) {
            if (p==0) break;
            int t;
            char c;
            while (scanf("%d%c",&t,&c)) {
                edg[t].push_back(p);
                edg[p].push_back(t);
                if (c=='\n') break;
            }
        }
        dfs(1,1,1);
        int sum=0;
        for (int x=1;n>=x;x++) {
            sum += cut_vertex[x];
        }
        printf("%d\n",sum);
    }
}


(UVA) 11686 - Pick up sticks

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=2733

主要是topological sort啦。比較需要注意的是N比較大(10^6),要小心不要co爛掉。



#include <iostream>
#include <stdio.h>
#include <queue>
#include <vector>
using namespace std;

const int MAX_N = 1e6 + 3;

int rudu[MAX_N];
vector<int> edg[MAX_N];
queue<int> que;
bool visit[MAX_N];
int ans[MAX_N];

int main (){
    int n,m;
    while (scanf("%d %d",&n,&m) != EOF) {
        if (!n && !m) break;
        for(int x=0;n>=x;x++) {
            edg[x].clear();
            rudu[x]=0;
            visit[x]=false;
        }
        for (int x=0;m>x;x++) {
            int i,j;
            scanf("%d %d",&i,&j);
            edg[i].push_back(j);
            rudu[j]++;
        }
        int id=0;
        for (int x=1;n>=x;x++) {
            if (rudu[x]==0 && visit[x]==false) {
                que.push(x);
                while (!que.empty()) {
                    int t=que.front();
                    ans[id++]=t;
                    visit[t]=true;
                    que.pop();
                    for (auto i=edg[t].begin();i!=edg[t].end();i++) {
                        int tmp=*i;
                        rudu[tmp]--;
                        if (rudu[tmp]==0) que.push(tmp);
                    }
                }
            }
        }
        if (id!=n) puts("IMPOSSIBLE");
        else {
            for(int x=0;id>x;x++) {
                printf("%d\n",ans[x]);
            }
        }
    }
}



(UVA) 11080 - Place the Guards

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=2021

用 "二分染色法" , 用BFS實作(DFS也可XD)


#include <iostream>
#include <stdio.h>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;

const int MAX_N = 203;
const int MAX_M = 10004;

int visit[MAX_N];
vector<int> edg[MAX_N];
queue<int> que;

int main () {
    int T;
    scanf("%d",&T);
    while (T--) {
        int n,m;
        scanf("%d %d",&n,&m);
        for (int x=0;n>=x;x++) {
            edg[x].clear();
            visit[x]=-1;
        }
        for (int x=0;m>x;x++) {
            int i,j;
            scanf("%d %d",&i,&j);
            edg[j].push_back(i);
            edg[i].push_back(j);
        }
        int ans=0;
        for (int x=0;n>x;x++) {
            if (visit[x]==-1) {
                que.push(x);
                int _[2]={1,0};
                visit[x]=0;
                while (!que.empty()) {
                    int t=que.front();
                    que.pop();
                    for (auto i=edg[t].begin();i!=edg[t].end();i++) {
                        int tmp=*i;
                        if (visit[tmp]==-1) {
                            visit[tmp] = 1-visit[t];
                            _[visit[tmp]]++;
                            que.push(tmp);
                        }
                        else if (visit[tmp]==visit[t]) {
                            ans=-1;
                        }
                    }
                }
                if (ans==-1) continue;
                else if (_[1]==0) ans+=_[0];
                else ans+= min(_[0],_[1]);
            }
        }
        printf("%d\n",ans);
    }
}


Codeforces Round #364 (Div. 2)

http://codeforces.com/contest/701

題目:
pA : http://codeforces.com/contest/701/problem/A
pB : http://codeforces.com/contest/701/problem/B
pC : http://codeforces.com/contest/701/problem/C
pD : http://codeforces.com/contest/701/problem/D
pE : http://codeforces.com/contest/701/problem/E
pF : http://codeforces.com/contest/701/problem/F

My solutinos :
pA : http://codeforces.com/contest/701/submission/19329561
pB : http://codeforces.com/contest/701/submission/19331053
pC : http://codeforces.com/contest/701/submission/19333717
pE : http://codeforces.com/contest/701/submission/19878556
pF : http://codeforces.com/contest/701/submission/19885355

題解:

pA :
題目大意:給你n個數字(2<=n<=100,n是偶數),請你找出n/2個配對(兩個數字為一個配對),使得這n/2個配對總和一樣(題目保證有解!)。

那就隨便唬爛一下就好啦XD。看你要開陣列存 or 開set or O(N^2)解,都可以。

pB :
題目大意:現在有一個n*n (1<=n<=10^5)的棋盤,以及m (1<=m<=min(n^2,10^5) 個城堡(相當於中國象棋的 車(ㄐㄩ))。每當下一個城堡時,問說有多少個格子不會被攻擊到。

這題有很多解法。我的作法是:紀錄現在有多少個row和col是有被城堡佔領的。之後再用數學解即可。

pC :
題目大意:給你一個序列(只包含大寫字母、小寫字母),請求出最短的長度,使得這個長度包含所有出現的字元。

使用爬行法(two pointers)!就okay囉!

pD :
聽說有數學解,可是我看不太懂。有好心人士願意告訴我的話,歡迎在下面留言 ^_^。

pE :
題目大意:給你一棵大小n(2<=n<=10^5)的樹。這其中有2*k個點是大學。你現在要把這些點連接起來,使得經過的路線總和最大!

有一個很神奇的想法是說:有一條邊,把樹分成兩半:一半有s個大學,另外一半就有2*k-s個大學,其中,這一條邊一定會經過min(s,2*k-s)次(有點greedy的想法,大概就是走越多越好的概念)。基於這個想法,我可以DFS整棵樹,在過程中,我就維護子樹有大學的數量,在求出答案,就okay了~~。

pF :
題目大意:給你一張有權重的無向圖(不保證強連通,可能有重邊、自環),v個節點(1<=v<=1000),e條邊(1<=e<=30000),以及兩個點s,t (s!=t)。現在你可以清掉c個邊(0<=c<=2),使得s不能走到t且清除的邊中,權重和最小。

分成三種case討論吧!

case 1 : c=0 --- 直接輸出答案即可!代表在圖中s走不到t。

case 2 : c=1 : 那你先找出任一一條s到t的路徑(看是要BFS or DFS皆可,總之想辦法用到O(E) ),接下來,找出圖中的割邊( 使用 low 函數),如果割邊是在那條路徑上的話,那就有可能是答案。

case 3 : c=2 : 先試著移除掉你找過那條路徑上的任意一個邊,然後再從新的圖中,再找出一條s到t 的路徑,然後再找一次割邊,跟case 1一樣。

期望複雜度:O(n * m),我寫的複雜度:O(n*m*lgn)


Codeforces Round #365 (Div. 2)

http://codeforces.com/contest/703

題目:
pA : http://codeforces.com/contest/703/problem/A
pB : http://codeforces.com/contest/703/problem/B
pC : http://codeforces.com/contest/703/problem/C
pD : http://codeforces.com/contest/703/problem/D
pE : http://codeforces.com/contest/703/problem/E

My solutions :
pA : http://codeforces.com/contest/703/submission/19618133
pB : http://codeforces.com/contest/703/submission/19622667
pD : http://codeforces.com/contest/703/submission/19768229

題解:

pA :
題目大意:判斷比賽的輸贏!

認真判斷即可!

pB :
題目大意:有n個城市(3<=n<=10^5),每個城市都有各自的ci值(1<=ci<=10000)。如果兩個城市i,j中間有連接,那連接的weight就是ci * cj。一開始,會形成一個環:城市 1 連接 城市 2 , 城市 2 連接 城市 3 , ...... 城市 n 連接 城市 1。 而這其中,會有k個首都(1<=k<=n),首都城市會與所有其他城市相連。問你說:整張圖的權重和。

先開一個sum值:記錄所有城市的ci和。接下來,對於每個首都j,ans += cj * (sum - cj),接下來再把環補起來。最後,我們要想辦法處理首都相乘的問題:可以利用數學公式(a1 + a2 + ..... + an) ^ 2 = (a1^2 + a2^2 + ..... + an^2) + 2 * (兩兩相乘) 解決。

pD :
題目大意:給你一個長度n(1<=n<=10^6)的序列,你只需要支援區間查詢[l,r]:區間中,出現偶數個數的數字的XOR和。

先把查詢按照右界排序。然後需要維護一個東西:前綴XOR和。之後答案就是 前綴XOR和 ^ (區間distinct的數字XOR和)。至於如何維護後面的東西:線段樹啦!







2016年8月15日 星期一

(UVA) 10004 - Bicoloring

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=24&problem=945

BFS一番即可XD

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;

const int MAX_N = 203;

int w[MAX_N][MAX_N];
int col[MAX_N];

int main () {
    int n;
    while (scanf("%d",&n) != EOF) {
        if (!n) break;
        int m;
        scanf("%d",&m);
        memset(w,0,sizeof(w));
        for (int x=0;m>x;x++) {
            int i,j;
            scanf("%d %d",&i,&j);
            w[i][j] = w[j][i] = 1;
        }
        queue<int> que;
        que.push(0);
        memset(col,-1,sizeof(col));
        bool ans=true;
        while (!que.empty()) {
            int t=que.front();
            que.pop();
            for (int x=0;n>x;x++) {
                if (w[t][x]==1 && col[x]==-1) {
                    col[x] = 1-col[t];
                    que.push(x);
                }
                else if (w[t][x]==1 && col[x]==col[t]) ans=false;
            }
        }
        printf("%s\n",ans?"BICOLORABLE.":"NOT BICOLORABLE.");
    }
}

Codeforces Round #367 (Div. 2)

http://codeforces.com/contest/706

題目;
pA : http://codeforces.com/contest/706/problem/A
pB : http://codeforces.com/contest/706/problem/B
pC : http://codeforces.com/contest/706/problem/C
pD : http://codeforces.com/contest/706/problem/D
pE : http://codeforces.com/contest/706/problem/E

My Solutions :
pA : http://codeforces.com/contest/706/submission/19788234
pB : http://codeforces.com/contest/706/submission/19790222
pC : http://codeforces.com/contest/706/submission/19797359
pD(1) : http://codeforces.com/contest/706/submission/19806189
pD(2) : http://codeforces.com/contest/706/submission/19823423

題解:
pA :
題目大意:給你一個固定點(a,b)以及n個(1<=n<=100)其他的點(xi,yi)。請求出其他點到固定點的最小距離。

那你就開一個計算距離的函式,認真維護距離一番。記得輸出答案的時候,要指定輸出的位數:(1) #include <iomanip>中,cout << fixed<<setprecision(位數) << num<<endl; (2) printf("%.位數f", num);

pB :
題目大意:給你n個數字(1<=n<=10^5),q比詢問(1<=q<=10^5),求有多少個數字小於等於mi。

求upper_bound或lower_bound即可XD。用法可以參考我的code

pC :
題目大意:現在有n個字串(1<=n<=10^5),你可以對字串i做出反轉這個動作,可是每當你反轉,就要花費ci。現在你需要把這n個字串按照字典序排好(C++ string中的大於&小於),請求出最少的花費。

那你就開一個兩條dp陣列(dp[2][MAX_N]),初始值是INF(無限大),dp[0][i]的意思是說以沒有反轉的i為結尾的最小cost,dp[1][i]是有反轉的。

遞迴的方式:dp[0][i] = min(dp[0][i] , dp[1][i-1] if valid , dp[0][i-1] if valid) , dp[1][i] = min(dp[0][i-1] + c[i] if valid, dp[1][i-1] + c[i] if valid)。

pD :
題目大意:維護一個很像multiset的資料結構:支援(1)插入 (2)刪除 (3)查詢,查詢是指給你一個數字i,求出max(i ^ j) ,其中j是在mutliset裡面,^是XOR運算。一開始multiset就有0

第一份solution的解法:用treap維護multiset。接下來,對於"查詢",先有一個greedy的概念:如果可以在越高的位元XOR成1,那就在越高的位元XOR成1。又因為數字範圍在1~10^9之間,所以位元最多只有lg 10^9 = 32次,對於每個位元,我把它分成0和1的部分,進行query,有比較高的XOR值,就先往那裏走,走到最後,就是答案了。複雜度 O(q lg q lg 10^9)

第二份:用trie存multiset,然後按照trie認真走即可 <(_ _)>


2016年8月10日 星期三

(UVA) 11060 - Beverages

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=24&problem=2001

題目大意:給你n個東西及m個限制。要求輸出符合m個限制的排列。如果兩兩間沒有特別的限制(在m裡面的限制),用輸入的順序判斷。

sol : 把寫topological 的 queue 改成 priority_queue 即可!!!

因為,用min heap的話,就變成可以維護相對關係了!

複雜度:O(n lg n)  //map + heap


#include <iostream>
#include <stdio.h>
#include <cstring>
#include <vector>
#include <queue>
#include <map>
using namespace std;

const int MAX_N = 103;

string s[MAX_N];
int rudu[MAX_N];
map<string,int> mp;
vector<int> edg[MAX_N];

int main () {
//    freopen("output.txt","w",stdout);
    //好久沒用cin XD ;
    int n;
    int cases=1;
    while (scanf("%d",&n) != EOF) {
        mp.clear();
        for (int x=0;n>x;x++) {
            rudu[x]=0;
            edg[x].clear();
        }
        for (int x=0;n>x;x++) {
            cin >> s[x];
            mp[s[x]] = x;
        }
        int m;
        scanf("%d",&m);
        for (int x=0;m>x;x++) {
            string a,b;
            cin >> a >> b;
            rudu[mp[b]] ++;
            edg[mp[a]].push_back(mp[b]);
        }
        printf("Case #%d: Dilbert should drink beverages in this order:",cases++);
        priority_queue<int,vector<int> , greater<int> > que;
        for (int x=0;n>x;x++) {
            if (rudu[x] == 0) que.push(x);
        }
        while (!que.empty()) {
            int t=que.top();
            que.pop();
            cout<<' '<<s[t];
            for (vector<int>::iterator i=edg[t].begin();i!=edg[t].end();i++) {
                int tmp=*i;
                rudu[tmp]--;
                if (rudu[tmp] == 0) que.push(tmp);
            }
        }
        puts(".\n");
    }
}

(UVA) 11094 - Continents

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=24&problem=203

注意事項:國王代表的點是陸地,其他都是水!!!

我是用DFS,其實也可以用BFS


#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;

const int MAX_N = 23;

char s[MAX_N][MAX_N];
int mp[MAX_N][MAX_N];

int dfs(int x,int y,int n,int m) {
    mp[x][y] = 0;
    int dx[4] = {0,0,1,-1},dy[4] = {1,-1,0,0};
    int ret=1;
    for (int i=0;4>i;i++) {
        int tx=(x + dx[i]), ty=(m+y+dy[i]) % m;
        if (0<=tx && tx<n && mp[tx][ty] == 1) {
            mp[tx][ty] = 0;
            ret += dfs(tx,ty,n,m);
        }
    }
    return ret;
}

int main () {
    int n,m;
    while (scanf("%d %d",&n,&m) != EOF) {
        memset(mp,0,sizeof(mp));
        getchar();
        for (int x=0;n>x;x++) {
            scanf("%s",s[x]);
        }
        int sx,sy;
        scanf("%d %d",&sx,&sy);
        for (int x=0;n>x;x++) {
            for (int y=0;m>y;y++) {
                mp[x][y] = (s[x][y] == s[sx][sy] ? 1 : 0);
            }
        }
        dfs(sx,sy,n,m);
        int ans=0;
        for (int x=0;n>x;x++) {
            for (int y=0;m>y;y++) {
                if (mp[x][y] == 1) ans = max(ans,dfs(x,y,n,m));
            }
        }
        printf("%d\n",ans);
    }
}

(UVA) 11906 - Knight in a War Grid

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=24&problem=3057

注意事項:
騎士從(0,0)開始走。 每到他可以走到的點 ,他會計算說,有多少個點可以走到這裡。 記得,他可以走到(0,0) 。 輸出有多少 偶數 & 奇數。

於是乎,debug好久,終於AC了

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <queue>
#include <utility>
using namespace std;

#define S second
#define F first
#define MP make_pair
typedef pair<int,int> pii;
const int MAX_N = 203;

int mp[MAX_N][MAX_N];
int can[MAX_N][MAX_N];

int f(int x,int y,int n,int m) {
    if (mp[x][y] == 0) return 0;
    int dx[8] = {n,n,-n,-n,m,m,-m,-m},dy[8] = {m,-m,m,-m,n,-n,n,-n};
    int ret=0;
    for (int i=0;8>i;i++) {
        //1-->okay
        int tx=x + dx[i],ty=y+dy[i];
        if (0<=tx && 0<=ty && mp[tx][ty] == 1) ret++;
    }
    return (n==m || n==0 || m==0 ? ret/2 : ret);
}

int main () {
//    freopen("output.txt","w",stdout);
    int T;
    scanf("%d",&T);
    for (int qq=1;T>=qq;qq++) {
        printf("Case %d: ",qq);
        int a,b,n,m;
        scanf("%d %d %d %d",&a,&b,&n,&m);
        memset(mp,0,sizeof(mp));
        memset(can,0,sizeof(can));
        can[0][0] = 1;
        for (int x=0;a>x;x++) {
            for (int y=0;b>y;y++) {
                mp[x][y]= 1;
            }
        }
        int q;
        scanf("%d",&q);
        while (q--) {
            int x,y;
            scanf("%d %d",&x,&y);
            mp[x][y] = 0;
        }
        int even=0,odd=0;
        queue<pii> que;
        que.push(MP(0,0));
        while (!que.empty()) {
            pii tmp = que.front();
            que.pop();
            int t=f(tmp.F,tmp.S,n,m);
            if (t!=0 && t%2==0 || t==0 && tmp == MP(0,0)) even++;
            else if (t%2==1) odd++;
            int dx[8] = {n,n,-n,-n,m,m,-m,-m},dy[8] = {m,-m,m,-m,n,-n,n,-n};
            int x=tmp.F, y=tmp.S;
//            cout<<endl<<x<<" "<<y<<endl;
            for (int i=0;8>i;i++) {
                int tx=x + dx[i],ty=y+dy[i];
                if (0<=tx && 0<=ty && mp[tx][ty] == 1 && can[tx][ty] == 0) {
                    que.push(MP(tx,ty));
                    can[tx][ty] = 1;
                }
            }
        }
        printf("%d %d\n",even,odd);
    }
}
/*
1
11 53 0 7
4
4 12
0 18
7 46
1 46
*/