abc212 差F

发布时间 2023-09-24 12:41:37作者: Bellala

abc212 差F

A - Alloy (5')

B - Weak Password (64')

C - Min Difference (246')
两个数组中各取一数,最小化差的绝对值

排序,各用一个指针

D - Querying Multiset (775')
三种操作:加入一个数x、所有数+x、输出并删除最小数

小根堆,维护全局add

E - Safety Journey (1410')
n个点的完全图删去m条边,问从点1出发最终回到点1的路径数。没有重边。n,m,k<=5000

如果是加边而不是删边,那大力dp就行了(迭代k次)
删边的话就用完全图来减

F - Greedy Takahashi (2332')

\(i\) 趟大巴在 \(s_i\) 时刻从 \(a_i\) 城市出发,并在 \(t_i\) 时刻到达 \(b_i\) 城市。每次询问在 \(x_i\) 时刻从 \(y_i\) 城市出发,等到车就上,在 \(z_i\) 时刻会在哪趟车或哪个城市。范围 \(1e5\)

啊?居然是倍增?

对城市+时间倍增是不现实的,应该对大巴倍增

倍增、二分要考虑边界问题啥的,我觉得还是有一点细节的吧。。调完代码之后看了下 tourist 的,他的代码真是优雅

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5, M = 18;
int n, m, q, f[N][M];
array<int, 4> bus[N];
vector<pair<int, int> > city[N];
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    
    cin >> n >> m >> q;
    for (int i = 1; i <= m; i++) {
        auto &[a, b, s, t] = bus[i];
        cin >> a >> b >> s >> t;
        city[a].push_back({s, i}); // startTime, busId
    }
    for (int i = 1; i <= n; i++)
        sort(city[i].begin(), city[i].end());
    
    // 计算 f[u][0]
    for (int u = 1; u <= m; u++) {
        auto [a, b, s, t] = bus[u];
        auto p = lower_bound(city[b].begin(), city[b].end(), make_pair(t, 0));
        f[u][0] = p == city[b].end() ? u : p->second; //留在原地或接着坐下一趟车
    }
    // 计算 f[u][1~18]
    for (int i = 1; i < M; i++) {
        for (int u = 1; u <= m; u++)
            f[u][i] = f[f[u][i - 1]][i - 1];
    }
    
    while (q--) {
        int x, y, z;
        cin >> x >> y >> z;
        auto p = lower_bound(city[y].begin(), city[y].end(), make_pair(x, 0));
        if (p == city[y].end() || p->first >= z) { //完全坐不了车
            cout << y << '\n';
        } else {
            int t = p->second;
            for (int i = M - 1; i >= 0; i--) { //旅途中的最后一趟车
                if (bus[f[t][i]][2] < z) t = f[t][i];
            }
            if (bus[t][3] >= z) cout << bus[t][0] << ' ' << bus[t][1] << '\n'; //最后在车上
            else cout << bus[t][1] << '\n'; //最后在目的地
        }
    }
    
    return 0;
}

G - Power Pair (2150')

原根还真能出题啊?长见识了

给定质数 \(p(\le 10^{12})\),询问有多少对 \(x,y\) 满足 \(0\le x, y\le p-1\) 且存在 \(m\) 使得 \(x^m\equiv y\pmod p\)

\(g\) 为模 \(p\) 的一个原根,那么 \(g^{1..p-1} \mod p\) 取遍 \(1..p-1\),那么 \(x,y\) 都可写成 \(g\) 的幂 \(x=g^a, y=g^b\) (这里假设 \(x,y>0\)
那么 \(g^{am}\equiv g^b \pmod p\)\(am\equiv b\pmod {p-1}\),注意模数是 \(p-1\)。下面记 \(n=p-1\)
此式有解当且仅当 \(\gcd(a,n)|b\),那么答案为 \(\sum\limits_{a=1}^{n}\frac {n}{\gcd(a,n)} = \sum\limits_{d|n}\frac {n}d f(d)\),其中 \(f(d)\) 表示 \([1,n]\) 中与 \(n\)\(\gcd\)\(d\) 的数有几个,实际上 \(f(d)=\varphi(\frac{n}d)\)。那么答案就是 \(\sum\limits_{d|n}d \varphi(d)\)
还有 \(x=y=0\) 的情况,最终答案记得 \(+1\)

看网上的题解好像直接求 \(\varphi\) 也能过,复杂度不太懂

官方题解:\(f(d)=\frac nd - \sum\limits_{d\neq x\and d|x}f(x)\),于是从大到小计算 \(f(d)\),复杂度 \(d^2\)

另外 AcWing 有个 \(O(质因子数*因子数)\) 的写法,我看了半天。居然也刚好不重不漏诶!真神奇

graph A((n=12)) B((6)) C((4)) D((3)) E((2)) F((1)) A ---|2| B A ---|3| C B ---|2| D C ---|2| E B ---|3| E D ---|3| F E ---|2| F
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll mod = 998244353;
void add(ll &x, ll y) {
    x = ((x + y) % mod + mod) % mod;
}
int main() {
    ll n;
    cin >> n;
    n--;
    
    vector<ll> ds;
    for (ll i = 1; i <= n / i; i++) if (n % i == 0) {
        ds.push_back(i);
        if (i != n / i) ds.push_back(n / i);
    }
    
    sort(ds.begin(), ds.end());

    vector<ll> f(ds.size());
    ll ans = 1;
    for (int i = ds.size() - 1; i >= 0; i--) { //O(d^2)
        f[i] = n / ds[i];
        for (int j = i + 1; j < ds.size(); j++) {
            if (ds[j] % ds[i] == 0) f[i] -= f[j];
        }
        f[i] %= mod;
        ans += n / ds[i] % mod * f[i] % mod;
    }
    cout << (ans % mod + mod) % mod;
    
    return 0;
}