1. 程式人生 > >洛谷 P1477 [NOI2008]假面舞會

洛谷 P1477 [NOI2008]假面舞會

amp pan () memset http fin 滿足 最大 line

題目鏈接

題目描述

一年一度的假面舞會又開始了,棟棟也興致勃勃的參加了今年的舞會。

今年的面具都是主辦方特別定制的。每個參加舞會的人都可以在入場時選擇一 個自己喜歡的面具。每個面具都有一個編號,主辦方會把此編號告訴拿該面具的人。

為了使舞會更有神秘感,主辦方把面具分為\(k(k≥3)\)類,並使用特殊的技術將每個面具的編號標在了面具上,只有戴第\(i\) 類面具的人才能看到戴第\(i+1\) 類面具的人的編號,戴第\(k\) 類面具的人能看到戴第1 類面具的人的編號。

參加舞會的人並不知道有多少類面具,但是棟棟對此卻特別好奇,他想自己算出有多少類面具,於是他開始在人群中收集信息。

棟棟收集的信息都是戴第幾號面具的人看到了第幾號面具的編號。如戴第2號面具的人看到了第5 號面具的編號。棟棟自己也會看到一些編號,他也會根據自己的面具編號把信息補充進去。

由於並不是每個人都能記住自己所看到的全部編號,因此,棟棟收集的信 息不能保證其完整性。現在請你計算,按照棟棟目前得到的信息,至多和至少有多少類面具。由於主辦方已經聲明了\(k≥3\),所以你必須將這條信息也考慮進去。

輸入輸出格式
輸入格式:

第一行包含兩個整數n, m,用一個空格分隔,n 表示主辦方總共準備了多少個面具,m 表示棟棟收集了多少條信息。接下來m 行,每行為兩個用空格分開的整數a, b,表示戴第a 號面具的人看到了第b 號面具的編號。相同的數對a, b 在輸入文件中可能出現多次。

輸出格式:

包含兩個數,第一個數為最大可能的面具類數,第二個數為最小可能的面具類數。如果無法將所有的面具分為至少3 類,使得這些信息都滿足,則認為棟棟收集的信息有錯誤,輸出兩個-1。

輸入樣例#1

6 5
1 2
2 3
3 4
4 1
3 5

輸出樣例#1:

4 4

輸入樣例#2:

3 3
1 2
2 1
2 3

輸出樣例#2:

-1 -1

說明

50%的數據,滿足\(n ≤ 300, m ≤ 1000\)

100%的數據,滿足\(n ≤ 100000, m ≤ 1000000\)

題解

顯然,
①如果有多個點指向同一個點,那麽他們屬於同一類別。
②一個點看到的所有點是一個種類。

那麽我們可以吧以上情況縮一下,具體就是給每個關系構一條-1的反邊

然後就在這條圖上操作
可以發現圖上會有環和鏈

對於鏈,不管\(k\)取多少都可以滿足

對於環,\(k\)滿足是環上點數的約數

那麽有環的情況,最大就為所以環點數的\(gcd\)


沒環就是所有鏈的長度和

對於最小的\(k\), 答案為最小的\(k(k \geq 3)\)滿足 \(k\)為所有環大小的約數
如果沒環,答案為\(3\)

Code

#include<bits/stdc++.h>
#define LL long long
#define RG register
using namespace std;

inline int gi() {
    int f = 1, s = 0;
    char c = getchar();
    while (c != '-' && (c < '0' || c > '9')) c = getchar();
    if (c == '-') f = -1, c = getchar();
    while (c >= '0' && c <= '9') s = s*10+c-'0', c = getchar();
    return f == 1 ? s : -s;
}
const int N = 100010;
struct node {
    int to, next, w;
}g[2000010];
int last[N], gl;
void add(int x, int y, int z) {
    g[++gl] = (node) {y, last[x], z};
    last[x] = gl;
    return ;
}

inline int gcd(int a, int b) {
    return !b ? a : gcd(b, a%b);
}

int cnt, Max[N], Min[N], dis[N], ans1, ans2;
bool flag[N];
void dfs(int u) {
    flag[u] = 1;
    Max[cnt] = max(Max[cnt], dis[u]);
    Min[cnt] = min(Min[cnt], dis[u]);
    for (int i = last[u]; i; i = g[i].next) {
        int v = g[i].to;
        if (!flag[v]) {
            dis[v] = dis[u]+g[i].w;
            dfs(v);
        }
        else {
            if (!ans1) ans1 = abs(dis[u]+g[i].w-dis[v]);
            else ans1 = gcd(ans1, abs(dis[u]+g[i].w-dis[v]));
        }
    }
    return ;
}

int main() {
    int n = gi(), m = gi();
    for (int i = 1; i <= m; i++) {
        int u = gi(), v = gi();
        add(u, v, 1); add(v, u, -1);
    }
    memset(Min, 127/3, sizeof(Min));
    for (int i = 1; i <= n; i++)
        if (!flag[i])
            ++cnt, dfs(i);
    if (!ans1) {
        for (int i = 1; i <= cnt; i++)
            ans1 += Max[i]-Min[i]+1;
        if (ans1 < 3)
            printf("-1 -1\n");
        else printf("%d 3\n", ans1);
        return 0;
    }
    if (ans1 < 3) {
        printf("-1 -1\n");
        return 0;
    }
    printf("%d ", ans1);
    for (int i = 3; i <= ans1; i++)
        if (ans1 % i == 0) {
            printf("%d\n", i);
            return 0;
        }
    return 0;
}

洛谷 P1477 [NOI2008]假面舞會