1. 程式人生 > 其它 >[HDU] 2020中國大學生程式設計競賽(CCPC) - 網路選拔賽 Graph Theory Class

[HDU] 2020中國大學生程式設計競賽(CCPC) - 網路選拔賽 Graph Theory Class


暴力很容易寫,找一下規律,可以發現:

實際上不用找規律,顯然\(2 \to p\),每個合數肯定是被某個質因子連上去

對於質數\(p(>3)\),首先有\(2 \to p\)的邊,之後有\(p \to p \cdot (p+2k)\)的邊,其中\(k=0,1,2,3,\cdots\)

最後連上\(2 \to *\),其中\(*\) 從未被連過

那就很容易發現,\(*\)只能是偶數或者素數

現在需要求mst

如果\(p+k=a \cdot b,a<p\),那麼\(p(p+k)=a \cdot pb=a \cdot (a+2k)\)

所以每個奇數\(t\)只會在其最小質因子處統計,這些邊的貢獻是\(t\)

\(2 \to p\)的貢獻是\(2p\)

\[\left( \sum_{2<p\le n+1,p \in \mathbb{P}} 2p \right)+\sum_{2 \le t \le n+1, t \not\in \mathbb{P}} t=\left( \sum_{i=3}^{n+1}i \right)+\sum_{2 < p \le n+1 ,p \in \mathbb{P}} p \]

懶得寫min25篩了,網上賀了個板子

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

int calc(int n) {
    vector<int> fa(n + 1);
    function<int(int)> getfa = [&] (int x) {
        return x == fa[x] ? x : fa[x] = getfa(fa[x]);
    };
    for(int i = 1 ; i <= n ; ++ i) {
        fa[i] = i;
    }
    int res = 0;
    function<int(int, int)> gcd = [&] (int a, int b) {
        return b ? gcd(b, a % b) : a;
    };
    auto lcm = [&] (int a, int b) {
        return a / gcd(a, b) * b;
    };
    vector<pair<int, pair<int, int> > > ed;
    for(int i = 1 ; i <= n ; ++ i) {
        for(int j = i + 1 ; j <= n ; ++ j) {
            ed.push_back({ lcm(i + 1, j + 1), { i, j } });
        }
    }
    vector<pair<pair<int, int>, int> > out;
    sort(ed.begin(), ed.end());
    for(auto e: ed) {
        int w = e.first;
        int u = e.second.first, v = e.second.second;
        if(getfa(u) != getfa(v)) {
//            printf("%d - %d (%d)\n", v + 1, u + 1, w);
//            printf("%d %d %d\n", v + 1, u + 1, w);
            out.push_back({ {u + 1, v + 1}, w }); 
            fa[getfa(u)] = getfa(v);
            res += w;
        }
    }
//    sort(out.begin(), out.end());
//    for(auto x: out) {
//        printf("%d %d %d\n", x.first.first, x.first.second, x.second);
//    }
    return res;
}

int calc_test(int n) {
    vector<int> vis(n + 5), fa(n + 5), linked(n + 5);
    function<int(int)> getfa = [&] (int x) {
        return x == fa[x] ? x : fa[x] = getfa(fa[x]);
    };
    for(int i = 2 ; i <= n + 1 ; ++ i) {
        fa[i] = i;
    }
    function<int(int, int)> gcd = [&] (int a, int b) {
        return b ? gcd(b, a % b) : a;
    };
    auto lcm = [&] (int a, int b) {
        return a / gcd(a, b) * b;
    };
    int res = 0;
    for(int i = 2 ; i <= n + 1 ; i += 2) vis[i] = 1;
    for(int i = 3 ; i <= n + 1 ; ++ i) {
        if(!vis[i]) {
            linked[i] = 1;
            res += lcm(2, i); 
            for(int j = i ; j <= n + 1 ; j += i) vis[j] = 1;
            for(int j = i ; i * j <= n + 1 && j <= n + 1 ; j += 2) {
                int t = i * j;
                if(!linked[t]) {
                    linked[t] = 1;
//                    cout << i << ' ' << t << endl;
                    res += lcm(i, t);
                }
            }
        }
    }
    for(int i = 3 ; i <= n + 1 ; ++ i) {
        if(!linked[i]) {
//            cout << 2 << ' ' << i << endl;
            res += lcm(2, i);
        }
    }
    return res;
}

int calc_test_test(int n) {
    vector<int> vis(n + 5);
    int res = 0;
    for(int i = 2 ; i <= n + 1 ; ++ i) {
        if(i > 2) {
            res += i;
        }
        if(!vis[i]) {
            if(i != 2) {
                res += i;
            }
            for(int j = i ; j <= n + 1 ; j += i) {
                vis[j] = 1;
            }
        }
    }
    return res;
}
typedef long long ll;
ll mod;
namespace getP {
    // http://www.shallowdreams.cn/?p=266
    // 不想寫了,粘的板子 
   const int N = 1000010;
    int prime[N], id1[N], id2[N], flag[N], ncnt, m;
    ll g[N], sum[N], a[N], T;
    ll n;
    int ID(ll x) {
        return x <= T ? id1[x] : id2[n / x];
    }
    ll calc(ll x) {
        return x * (x + 1) / 2 - 1;
    }
    ll f(ll x) {
        return x;
    }
    ll init(ll n){
        T = sqrt(n + 0.5);
        for (int i = 2; i <= T; i++) {
            if (!flag[i]) prime[++ncnt] = i, sum[ncnt] = sum[ncnt - 1] + i;
            for (int j = 1; j <= ncnt && i * prime[j] <= T; j++) {
                flag[i * prime[j]] = 1;
                if (i % prime[j] == 0) break;
            }
        }
        for (ll l = 1; l <= n; l = n / (n / l) + 1) {
            a[++m] = n / l;
            if (a[m] <= T) id1[a[m]] = m; else id2[n / a[m]] = m;
            g[m] = calc(a[m]);
        }
        for (int i = 1; i <= ncnt; i++)
            for (int j = 1; j <= m && (ll)prime[i] * prime[i] <= a[j]; j++)
                g[j] = g[j] - (ll)prime[i] * (g[ID(a[j] / prime[i])] - sum[i - 1]);
    }
    ll solve(ll x){
        if(x<=1){return x;}
        memset(g,0,sizeof(g));
        	memset(a,0,sizeof(a));
        	memset(sum,0,sizeof(sum));
        	memset(prime,0,sizeof(prime));
    	memset(id1,0,sizeof(id1));
    	memset(id2,0,sizeof(id2));
    	memset(flag,0,sizeof(flag));
    	ncnt=m=0;
        return n=x,init(n),g[ID(n)];
    }
}

typedef long long ll;
ll nekkonya(ll n) {
    // 2 ~ n + 1
    if(n == 1) return 0;
    else if(n == 2) return 6;
    else if(n == 3) return 10;
    else if(n == 4) return 20;
    else if(n == 5) return 26;
    
    ll res = getP :: solve(n + 1) - 2;
    res %= mod;
    res += (ll) (3 + n + 1) % mod * ((n - 1) % mod) % mod * ((mod + 1) / 2) % mod;
    res %= mod;
    res = (res + mod) % mod;
    return res;
}

int main() {
    int t; cin >> t;
    while(t --) {
        ll n;
        cin >> n >> mod;
        cout << nekkonya(n) << endl;
    }
}