牛客寒假训练赛2-I-本质理解筛法

1.前言:

这个题目还是挺不错的。我只想出了一个 O ( n l o g n ) O(nlogn) O(nlogn)的方法。对于 O ( n ) O(n) O(n)的欧拉筛+积性函数的方法完全忘干净了。这个题目出题人从一种非常优秀的角度看待这个问题。让这个问题变得非常明了简洁.赞!

2.素数筛法的本质:

素数筛法的本质就是构造一颗筛法DAG。两点之间有边当且仅当它们满足筛法的条件.

例如:
1.普通埃筛:构造DAG的特点:任意两个成倍数关系的数之间都连接有一条边。

复杂度:无非就是分析边的个数.那就分析每个点的出度呗。 ∑ i = 1 n n i = n l o g n \sum_{i=1}^{n}\frac{n}{i}=nlogn i=1nin=nlogn.

2.素数优化埃筛:构造的DAG的特点:任意一个质数与它的倍数之间形成一条链

复杂度:根据素数倒数和定理有: O ( n l o g l o g n ) O(nloglogn) O(nloglogn).

3.线性筛:构造的DAG的特点:任意一个大的数只会连向 G p 1 \frac{G}{p_1} p1G.也就是除掉一个最小质因子后的数.我们发现这个DAG有 n n n个点,除了 1 1 1以外,每个数都会往恰好一个小的数连接一条边。所以是 n − 1 n-1 n1条边。所以是颗树

复杂度:这个时候就显然了,复杂度严格在 O ( n ) O(n) O(n).

那么有DAG,自然就会有一些dp问题。例如:

小米ICPC预选赛-A:数论,dp

当然还有本题.

3.题目大意:

f ( i ) f(i) f(i)为将其质因分解后对质数排序组成的十进制数.求 ∑ i = 2 n f ( i ) \sum_{i=2}^nf(i) i=2nf(i).

4.题目思路:

脑子里有了那颗树,一切都显然了。我们可以单纯的对每个数走到根节点,求出 f ( i ) f(i) f(i).但是也可以用 d p dp dp.这里我们之前称之为积性函数。这里从动态规划的角度来讲就是一个符合乘法的转移式。

由于我们的边一定是最小质因子。所以转移的时候 f [ i ∗ p [ j ] ] f[i*p[j]] f[ip[j]]一定是在 f ( i ) f(i) f(i)的开头拼接上 p [ j ] p[j] p[j]。这个时候就还需要记录一个长度。转移就完事了。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
const int maxn = 4e6 + 5;
const int mod = 1e9 + 7;
int bk[maxn] , cnt;
ll p[maxn / 4] , f[maxn] , g[maxn] , ans;
ll solve (int n)
{
    
    
    for (int i = 2 ; i <= n ; i++){
    
    
        if (!bk[i]){
    
    
            p[++cnt] = i;
            f[i] = i;
            int x = i;
            g[i] = 1;
            while (x){
    
    
                x /= 10;
                g[i] *= 10;
            }
        }
        for (int j = 1 ; j <= cnt && p[j] * i <= n ; j++){
    
    
            bk[i * p[j]] = 1;
            f[i * p[j]] = (f[i] + g[i] * f[p[j]]%mod)%mod;
            g[i * p[j]] = g[i] * g[p[j]]%mod;
            if (i % p[j] == 0) break;
        }
    }
    for (int i = 2 ; i <= n ; i++){
    
    
        ans = (ans + f[i]) % mod;
    }
    return ans;
}
int main()
{
    
    
    ios::sync_with_stdio(false);
    int n; cin >> n;
    cout << solve(n) << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35577488/article/details/114856020