2019 ICPC 徐州ネットワーク コンペティション J.ランダム アクセス イテレーター

2019 ICPC 徐州ネットワーク コンペティション J.ランダム アクセス イテレーター


このトピックの主なアイデア : n 個の点と n-1 個のエッジ (ツリー構造) を与え、1 がルート ノードであることを確認し、次の方法で dfs を走査します: dfs が最も深いノードに到達する確率を尋ねます (
ここに画像の説明を挿入
if最も深いノードは複数あり、どれか 1 つで十分です))、答えはモジュロ 1e9+7 です。

解決策: この確率の問題は競技会の最後の 1 時間に公開され、AC は最後の 10 分間に行われました。ちょっと難しそうに見えますが、実はdp処理です。まず、dfs を通じて各ノードの深さと子の数を見つけ、次に最も深いノードの dp 値を 1 に設定します。(dp[i] は、dfs がノード i に到達した後に最も深い点までの dfs が成功する確率を示します)。 dp を下から更新: 任意のノード u について、x 個の子があり、それぞれの dp 値が dp[v1]、dp[v2]、dp[v3]...dp[vx] であると仮定します。ルールがあります。 dfs がノード u に到着した後、それが繰り返されることを知るには、dfs を x 回実行した後の成功確率を直接計算するのは困難ですが、負の側を考慮して、x 回のすべての失敗の確率を求めます。x 個のイベントは独立しているため、失敗する確率を x 乗して 1 回求めるだけで十分です。失敗は簡単です。つまり、(1-dp[v1])*(1-dp[v2])...(1-dp[vx])/x です。

以下はACコードです。

#include <bits/stdc++.h>
using namespace std;
using namespace chrono;
const int N = 2000005;
const int M = 1000000007;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1);
const double eps = 1e-8;
#define ms(x, y) memset((x), (y), sizeof(x))
#define mc(x, y) memcpy((x), (y), sizeof(y))
typedef long long ll;
typedef unsigned long long ull;
#define fi first
#define se second
#define mp make_pair
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
#define bg begin
#define ed end
#define pb push_back
#define al(x) (x).bg(), (x).ed()
#define st(x) sort(al(x))
#define un(x) (x).erase(unique(al(x)), (x).ed())
#define fd(x, y) (lower_bound(al(x), (y)) - (x).bg() + 1)
#define ls(x) ((x) << 1)
#define rs(x) (ls(x) | 1)
template <class T>
bool read(T & x) {
    
    
    char c;
    while (!isdigit(c = getchar()) && c != '-' && c != EOF);
    if (c == EOF) return false;
    T flag = 1;
    if (c == '-') {
    
     flag = -1; x = 0; } else x = c - '0';
    while (isdigit(c = getchar())) x = x * 10 + c - '0';
    x *= flag;
    return true;
}
template <class T, class ...R>
bool read(T & a, R & ...b) {
    
    
    if (!read(a)) return false;
    return read(b...);
}
mt19937 gen(steady_clock::now().time_since_epoch().count());
struct edge {
    
     int to, next; } e[N];
int head[N], cnt = 0, sz[N], dep[N], leaf[N];
ll dp[N];
ll qpow(ll a, ll n, ll p) {
    
    
    ll r = 1;
    for (a %= p; n; n >>= 1, (a *= a) %= p)
        if (n & 1) (r *= a) %= p;
    return r;
}
void add(int u, int v) {
    
    
    e[cnt] = {
    
    v, head[u]};
    head[u] = cnt++;
}
void dfs(int d, int u, int p) {
    
    
    dep[u] = d;
    for (int i = head[u]; ~i; i = e[i].next) {
    
    
        int v = e[i].to;
        if (v == p) continue;
        sz[u]++;
        dfs(d + 1, v, u);
    }
    if (sz[u] == 0) leaf[u] = 1;
}
void dfs2(int u, int p) {
    
    
    if (leaf[u]) return;
    for (int i = head[u]; ~i; i = e[i].next) {
    
    
        int v = e[i].to;
        if (v == p) continue;
        dfs2(v, u);
        dp[u] = (dp[u] + (1 - dp[v] + M) % M) % M;
    }
    dp[u] = dp[u] * qpow(sz[u], M - 2, M) % M;
    dp[u] = qpow(dp[u], sz[u], M);
    // if (u == 1)
    //     cout << "check: " << dp[u] << ' ' << sz[u] << endl;
    dp[u] = (1 - dp[u] + M) % M;
    // if (u == 1)
    //     cout << "check: " << dp[u] << ' ' << sz[u] << endl;
}
int main()
{
    
    
    time_point<steady_clock> start = steady_clock::now();

    int size = 128 << 20;
    char * p = (char *)malloc(size) + size;
    #if (defined _WIN64) or (defined __unix)
        __asm__("movq %0, %%rsp\n" :: "r"(p));
    #else
        __asm__("movl %0, %%esp\n" :: "r"(p));
    #endif

    // cout << 39 * qpow(64, M - 2, M) % M << endl;
    // cout << 25 * qpow(64, M - 2, M) % M << endl;

    int n, u, v;
    read(n);
    ms(head, -1);
    for (int i = 1; i < n; i++) {
    
    
        read(u, v);
        add(u, v);
        add(v, u);
    }
    dfs(1, 1, 0);
    int mx = 0;
    for (int i = 1; i <= n; i++)
        if (leaf[i]) mx = max(mx, dep[i]);
    for (int i = 1; i <= n; i++) {
    
    
        if (leaf[i]) {
    
    
            if (dep[i] == mx) {
    
    
                dp[i] = 1;
            } else dp[i] = 0;
        }
    }
    dfs2(1, 0);
    // cout << "------------------" << endl;
    // for (int i = 1; i <= n; i++) cout << i << ' ' << dp[i] << endl;
    // cout << "------------------" << endl;
    printf("%lld\n", dp[1]);

    cerr << endl << "------------------------------" << endl << "Time: "
         << duration<double, milli>(steady_clock::now() - start).count()
         << " ms." << endl;

    exit(0);
}

おすすめ

転載: blog.csdn.net/yzsjwd/article/details/100608726