返回顶部

The Preliminary Contest for ICPC Asia Nanjing 2019

B. super_log

https://nanti.jisuanke.com/t/41299

很容易推出来是一个连续的幂次。这里主要是要知道扩展欧拉定理对互质肯定也是生效的,不需要整这么多东西。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int qpow2(ll x, int n, int m) {
    int _2m = m + m;
    ll res = 1;
    while(n) {
        if(n & 1) {
            res = res * x;
            if(res >= _2m)
                res = (res % m) + m;
        }
        x = x * x;
        if(x >= _2m)
            x = (x % m) + m;
        n >>= 1;
    }
    return res;
}

bool np[1000005];
int phi[1000005];
int pri[800005];
int ptop;

void sieve(int n) {
    np[1] = 1;
    phi[1] = 1;
    for(int i = 2; i <= n; ++i) {
        if(!np[i]) {
            pri[++ptop] = i;
            phi[i] = i - 1;
        }
        for(int j = 1; j <= ptop; ++j) {
            int t = i * pri[j];
            if(t > n)
                break;
            np[t] = 1;
            if(!(i % pri[j])) {
                phi[t] = phi[i] * pri[j];
                break;
            } else
                phi[t] = phi[i] * (pri[j] - 1);
        }
    }
}

int solve(int a, int b, int m) {
    if(m == 1 || b == 0)
        return 1;
    else
        return qpow2(a, solve(a, b - 1, phi[m]), m);
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    sieve(1000000);
    int T;
    scanf("%d", &T);
    while(T--) {
        int a, b, m;
        scanf("%d%d%d", &a, &b, &m);
        printf("%d\n", solve(a, b, m) % m);
    }
}

D. Robots

https://nanti.jisuanke.com/t/41301

这个题目的DAG我已经不知道吐槽什么好了。说一下花费的期望是怎么来的,事实上和天数的期望是一个道理。

据说可以把每一天的花费反过来,但为什么这样是等价的?

注意下面这个是倒推,就是用 \(day[i]\) 表示从 \(i\) 号点开始到达 \(n\) 号点的期望天数。

\(u\) 点可以到达 \(v_1,v_2,v_3\) ,那么天数的期望明显有 \(day[u]=\frac{1}{3+1}(day[v_1]+day[v_2]+day[v_3]+day[u])+1\)

\(cost[i]\) 表示从 \(i\) 号点开始到达 \(n\) 号点的期望花费,那么花费的期望明显有 \(cost[u]=\frac{1}{3+1}(cost[v_1]+cost[v_2]+cost[v_3]+cost[u])+day[u]\)

由定义明显有 \(day[n]=0\)\(cost[n]=0\)

qls的办法更好:

求花费的期望,假设由上面的方法得到了期望的天数。

那么答案为:
\(EX[cost[1]]=\sum\limits_{i=0}\frac{i*(i+1)}{2}p_i=\frac{1}{2}(\sum\limits_{i=0}i^2p_i+\sum\limits_{i=0}ip_i)\)

那么需要求的是前一项。

\(EX[(X+1)^2]=EX[X^2]+2EX[X]+1\)

得到后面的转移。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXN = 1e5 + 5;
int n, m;
vector<int> G[MAXN], AG[MAXN];
int outdeg[MAXN];
double day[MAXN], day2[MAXN];

queue<int> Q;
void topo() {
    day[n] = 0.0;
    day2[n] = 0.0;
    for(auto p : AG[n]) {
        --outdeg[p];
        if(!outdeg[p]) {
            Q.push(p);
        }
    }
    while(!Q.empty()) {
        int u = Q.front();
        Q.pop();
        int od = (int)G[u].size();
        day[u] = 1.0;
        for(auto v : G[u])
            day[u] += day[v] + 1.0;
        day[u] /= od;
        day2[u] = (2.0 * day[u] + 1.0);
        for(auto v : G[u]) 
            day2[u] += day2[v] + 2.0 * day[v] + 1.0;
        day2[u] /= od;
        for(auto p : AG[u]) {
            --outdeg[p];
            if(!outdeg[p]) {
                Q.push(p);
            }
        }
    }
    return;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int T;
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; ++i) {
            G[i].clear();
            AG[i].clear();
            outdeg[i] = 0;
        }
        for(int i = 1; i <= m; ++i) {
            int u, v;
            scanf("%d%d", &u, &v);
            G[u].push_back(v);
            AG[v].push_back(u);
            ++outdeg[u];
        }
        topo();
        printf("%.2f\n", 0.5 * (day2[1] + day[1]));
    }
}
posted @ 2019-09-01 19:33  Inko  阅读(163)  评论(0编辑  收藏  举报