1002:http://acm.hdu.edu.cn/showproblem.php?pid=6889\
题意:给你一个有n个点的图,结点编号1-n。节点i和j之间的边缘权重大小是lcm(i+1,j+1)。要你给出最小生成树的所有边缘的权重的和。
思路:不妨假设i<j。两点之间的边缘权重既然是lcm(i+1,j+1)。对于j+1是合数的边,我们只要让它连在它的质因数节点上就可以最小化lcm(i+1,j+1),这个值就是j+1。那么如果是质数呢? 很明显,直接和i=1连接,这时候它的边缘权重就是(j+1)*2。和其他的点链接边缘权重都一定比这个大。那么这么一来答案就是(3~ n+1)中所有质数的两倍再加上所有合数。再来化简,这个答案就是所有(3~ n+1)的质数的和加上(3~ n+1)的所有数的和。这时候就考虑用什么方法来求所有质数的和了。一看数据1e10,这时候发现欧拉筛已经不行了,于是打开baidu,输入百亿以内质数的和,你可以发现 知乎 上有一些方法求十亿以内的和只要0.057秒!!!,只要拿过来改改就是答案了。接着这题就不再有任何难度了。(嘘,当时找到的时候,我和两个队友都懵了,觉得这根本不是算法,而是魔法)

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


const int maxn = 1000010;
int prime[maxn], id1[maxn], id2[maxn], flag[maxn], ncnt, m;

ll g[maxn], sum[maxn], a[maxn], T, n;

namespace Min25 {
    inline int ID(ll x) {
        return x <= T ? id1[x] : id2[n / x];
    }

    inline ll calc(ll x) {
        return x * (x + 1) / 2 - 1;
    }

    inline ll f(ll x) {
        return x;
    }

    inline void init() {
        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]);
    }

    inline ll solve(ll x) {
        if (x <= 1) return x;
        return n = x, init(), g[ID(n)];
    }

}
int main()
{
    int t;
    cin>>t;
    ll nnn,kkk;
    while(t--)
    {

        cin>>nnn>>kkk;
        memset(prime, 0, sizeof(prime));
        memset(id1, 0, sizeof(id1));
        memset(id2, 0, sizeof(id2));
        memset(flag, 0, sizeof(flag));

        memset(g, 0, sizeof(g));
        memset(sum, 0, sizeof(sum));
        memset(a, 0, sizeof(a));
        T = 0; n = 0; ncnt = 0; m = 0;

        cout<<( (Min25::solve(nnn+1)-2)%kkk   +  (((nnn+1+3)%kkk)*((nnn-1)%kkk)/2)%kkk )  %kkk <<endl;
        //这个就是计算3~n+1的质数的和 与 3~n+1 的所有数的和
    }
    return 0;
}