2020 CCPC 网络赛1002—— Graph Theory Class

刚签完到就上min_25筛233
好!很有精神!

思路:构造
每个点若要加入原有图,那么所需的代价最低是它本身,最多与2相连,也就是这个数的两倍。显然,最终的答案是10^10以内的质数和*2+合数和。
也就是10^10以内的所有数之和+质数和
我们考虑用min_25筛解决
我们设F(i) = i(当i为质数的时候)
显然质数之和为
在这里插入图片描述
我们设函数g(n,j)为求出1到n中,i为质数或i的最小质因子大于当前第j个质数的f ( i )。其中 p j p_j pj表示第j个质数
在这里插入图片描述
显然我们要求的就是g(n,0)
对于这个式子,我们可用递归的方式解决
在这里插入图片描述
好吧,相信到这里,会的还是会,不会的还是不会(bushi)
最后,上代码

#include<bits/stdc++.h>
#define N 200010
#define ll long long
#define int long long
using namespace std;
ll mod = 0;
bool Prime[N];
int tot;
ll p[N];
ll n, sq, w[N], m, sum1[N], g1[N], id1[N], id2[N];
void xxs() {
    
     // 线性筛模板 
    for(int i = 2; i <= sq; i++) {
    
    
        if(!Prime[i]) ++tot, p[tot] = i;
        for(int j = 1; p[j] * i <= sq && j <= tot; j++) {
    
    
            Prime[p[j] * i] = 1;
            if(i % p[j] == 0) break;
        }
    }
    for(int i = 1; i <= tot; i++) {
    
    
    //注意这里的+p[i],实际上是相当于+x,如果求质数个数,那就是+1,如果是质数个数的平方和,那就是p[i]*p[i]
        sum1[i] = (sum1[i - 1] + p[i]) % mod;
    }
}
ll getid(ll x) {
    
     
    if(x <= sq) return id1[x];
    else return id2[n / x];
}
ll f1(ll x) {
    
     // 1~x 实际上是f(i) 的前缀和
    x %= mod;
    return x * (x + 1) / 2 % mod;
}
void min_25_dp()//求g(i,0),递推做 
{
    
    
    for(int i = 1; i <= tot; i++) {
    
    
        for(int j = 1; j <= m && p[i] * p[i] <= w[j]; j++) {
    
    
            g1[j] = (g1[j] - p[i] * (g1[getid(w[j] / p[i])] - sum1[i - 1]) % mod + mod) % mod;
        }
    }	
}
signed main() {
    
    
	
    scanf("%lld", &n),n++; 
    scanf("%lld",&mod);
	sq = sqrt(n), xxs();
    
    for(ll l = 1, r; l <= n; l = r + 1) {
    
    
        r = (n / (n / l)), w[++m] = (n / l);
        g1[m] = f1(w[m]) - 1;
        if(w[m] <= sq) id1[w[m]] = m;
        else id2[n / w[m]] = m;
    }
	min_25_dp();
    printf("%lld\n", (g1[getid(n)]%mod+(n)*(n+1)/2%mod-5) % mod);//	所有数之和+质数和,减5是因为从2开始,并且2不算
    return 0;
}

猜你喜欢

转载自blog.csdn.net/naiue/article/details/108716885