1. 程式人生 > >【Atcoder - AGC027C】ABland Yard

【Atcoder - AGC027C】ABland Yard

@ABland [email protected]


@題目描述 - [email protected]

Time Limit: 2 sec / Memory Limit: 1024 MB

Score : 900 points

Problem Statement
You are given an undirected graph consisting of N vertices and M edges.The vertices are numbered 1 to N, and the edges are numbered 1 to M. In addition, each vertex has a label, A or B. The label of Vertex i is si. Edge i bidirectionally connects vertex ai and bi.

The phantom thief Nusook likes to choose some vertex as the startpoint and traverse an edge zero or more times. Today, he will make a string after traveling as above, by placing the labels of the visited vertices in the order visited, beginning from the startpoint.

For example, in a graph where Vertex 1 has the label A and Vertex 2 has the label B, if Nusook travels along the path 1→2→1→2→2, the resulting string is ABABB.

Determine if Nusook can make all strings consisting of A and B.

Constraints
2≤N≤2×10^5, 1≤M≤2×10^5
|s|=N, si is A or B.
1≤ai,bi≤N
The given graph may NOT be simple or connected.

Input
Input is given from Standard Input in the following format:
N M
s
a1 b1
……
aM bM

Output
If Nusook can make all strings consisting of A and B, print Yes; otherwise, print No.

Sample Input 1
2 3
AB
1 1
1 2
2 2
Sample Output 1
Yes

Since Nusook can visit Vertex 1 and Vertex 2 in any way he likes, he can make all strings consisting of A and B.
題目描述圖1

Sample Input 2
4 3
ABAB
1 2
2 3
3 1
Sample Output 2
No

For example, Nusook cannot make BB.
The given graph may not be connected.
題目描述圖2

Sample Input 3
13 23
ABAAAABBBBAAB
7 1
10 6
1 11
2 10
2 8
2 11
11 12
8 3
7 12
11 2
13 13
11 9
4 1
9 7
9 6
8 13
8 6
4 10
8 7
4 3
2 1
8 12
6 9
Sample Output 3
Yes

Sample Input 4
13 17
BBABBBAABABBA
7 1
7 9
11 12
3 9
11 9
2 1
11 5
12 11
10 8
1 11
1 8
7 7
9 10
8 8
8 12
6 2
13 11
Sample Output 4
No

@中文題意@

n點m邊的圖(可自環可重邊),給每個點附上權值’A’或’B’。一條路徑(可經過重複邊)的權值為從起點到終點的所有點的權值相連成的字串。

問是否對於任意一個由‘A’, ‘B’組成的串,都存在一條路徑的權值等於它。

@分析@

【結論題嘛……我也不太好說】
先說對於自環。我們可以把一個結點拆成兩個結點,這兩個結點與其他結點的連邊情況是一模一樣的。然後,假如這個點有一個自環,則連通這兩個結點。可以發現這個拆點後的圖與原圖是等價的。

假設某一個串中有一個A,且它前後都為B。則我們可以由一個B結點出發,走到任意一個相鄰的A結點,再走回B結點,以構造串中這個單獨的A。

假設某一個串中有x個連續的A(x>2),且它前後都為B。則我們可以由一個B結點出發,走到一個相鄰的A結點,再從這個A結點出發走一個全部都由A結點組成的、長度為(x-1)的環,回到這個A結點,並回到它之前的B結點,以構造串中連續的A。

但是——假設某一個串中有兩個連續的A(x>2),且它前後都為B。不管圖長什麼樣子,我們都不能按照上面的方式來做(注意沒有自環)。

上面的例子即是對於“AABBAABB……”型的無限長串,我們必須針對它進行構造。

@結論@

如果有一個形如AABBAABBAABB……型的環,則答案為Yes
【這個結論……說實話我是猜出來的】
【2018/9/16 UPD:官方題解也沒說為什麼……還真TM是結論題】

我們這樣進行轉換:
如果一條邊連線的兩個點點權相同,則邊權為1;否則邊權為0。問題等價於:是否存在一個環,環上的邊權是形如10101010101一樣交替出現的。
再轉換:我們再拆點,將a拆成a1與a2。a1表示入邊邊權為0,出邊邊權為1的點;a2表示入邊邊權為1,出邊邊權為0的點。於是在新圖裡面出現的環就等價於原圖的101010101環。
這樣,只需要再拓撲排序判斷圖中是否存在環即可。

@程式碼@

……我估計你們也是看不懂程式碼的。
不過還是支援詢問啦,有什麼不解我盡力回答qwq

#include<cstdio>
#include<queue>
using namespace std;
const int MAXN = 200000;
const int MAXM = 2000000;
struct edge{
    int to;
    edge *nxt;
}edges[MAXM + 5], *adj[4*MAXN + 5], *ecnt = &edges[0];
char s[MAXN + 5];
void addedge(int u, int v) {
    edge *p = (++ecnt);
    p->to = v, p->nxt = adj[u], adj[u] = p;
}
int indeg[4*MAXN + 5];
int main() {
    int N, M;
    scanf("%d%d", &N, &M);
    scanf("%s", s+1);
    for(int i=1;i<=M;i++) {
        int a, b;
        scanf("%d%d", &a, &b);
        if( a == b ) {
            addedge(a+N, a+2*N);
            addedge(a+3*N, a);
        }
        else {
            if( s[a] == s[b] ) {
                addedge(a+N, b);
                addedge(b+N, a);
                addedge(a+3*N, b);
                addedge(b+N, a+2*N);
                addedge(b+3*N, a);
                addedge(a+N, b+2*N);
                addedge(a+3*N, b+2*N);
                addedge(b+3*N, a+2*N);
            }
            else {
                addedge(a, b+N);
                addedge(b, a+N);
                addedge(a+2*N, b+N);
                addedge(b, a+3*N);
                addedge(b+2*N, a+N);
                addedge(a+2*N, b+N);
                addedge(a+2*N, b+3*N);
                addedge(b+2*N, a+3*N);
            }
        }
    }
    for(int i=1;i<=4*N;i++) {
        for(edge *p=adj[i];p!=NULL;p=p->nxt)
            indeg[p->to]++;
    }
    queue<int>que;
    for(int i=1;i<=4*N;i++)
        if( !indeg[i] ) que.push(i);
    int cnt = 0;
    while( !que.empty() ) {
        cnt++;
        int f = que.front(); que.pop();
        for(edge *p=adj[f];p!=NULL;p=p->nxt) {
            indeg[p->to]--;
            if( !indeg[p->to] ) que.push(p->to);
        }
    }
    if( cnt == 4*N ) puts("No");
    else puts("Yes");
}

@[email protected]

就是這樣,新的一天裡,也請多多關照哦(ノω<。)ノ))☆.。~