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");
    }
}