• CF1559E Mocha and Stars(dp+莫比乌斯反演)


    求有多少长 n n n 的序列 a a a 满足:

    • l i ≤ a i ≤ r i l_i\le a_i\le r_i liairi
    • ∑ i = 1 n a i ≤ m \sum_{i=1}^{n}a_i\le m i=1naim
    • gcd ⁡ ( a 1 , … , a n ) = 1 \gcd(a_1,\dots,a_n)=1 gcd(a1,,an)=1

    答案对 998244353 998244353 998244353 取模

    样例输入 #1

    2 4
    1 3
    1 2
    
    • 1
    • 2
    • 3

    样例输出 #1

    4
    
    • 1

    只看前两个条件,我们发现就直接是一个背包问题,枚举 a i a_i ai,枚举背包状态,然后遍历所有的位置,时间复杂度是 O ( m 2 n ) O(m^2n) O(m2n),很显然,这个时间复杂度不能满足我们的要求,需要注意的是,题目问的是 < = m <=m <=m

    dp[0]=1;//意义是:恰好等于下标的种类数
    for(int i=1;i<=n;i++){
        memset(f,0,sizeof f);
        for(int j=l[i];j<=r[i];j++){
            for(int k=j;k<=m;j++){
                f[k]+=dp[k-j];
            }
        }
        dp[0]=0;
        for(int j=1;j<=m;j++)dp[i]=dp[i]+f[i];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    但是其实我们发现,中间的状态转移,用前缀和就可以完美解决

    for(int i=0;i<=m;i++)dp[i]=1;//意义是:小于等于下标的种类数(因此使用前缀和)
    for(int i=1;i<=n;i++){
        memset(f,0,sizeof f);
        for(int j=l[i];j<=m;j++){
            f[j]+=dp[j-l[i]];
            if(j>r[i]){
                f[j]-=dp[j-r[i]-1];//要[l[i],r[i]]区间的数,大于r[i]的数无法转移,因此减掉
            }
        }
        dp[0]=0;
        for(int j=1;j<=m;j++)dp[i]=dp[i-1]+f[i];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    时间复杂度是 O ( n m ) O(nm) O(nm)还可以~

    于是现在求的问题就是

    ∑ a 1 = l [ 1 ] r [ 1 ] ∑ a 2 = l [ 2 ] r [ 2 ] . . . ∑ a n = l [ n ] r [ n ] f ( a 1 , a 2 . . . a n ) ∗ [ g c d ( a 1 , a 2 . . . a n ) = 1 ] \displaystyle\sum_{a_1=l[1]}^{r[1]}\displaystyle\sum_{a_2=l[2]}^{r[2]}...\displaystyle\sum_{a_n=l[n]}^{r[n]}f(a_1,a_2...a_n)*[gcd(a_1,a_2...a_n)=1] a1=l[1]r[1]a2=l[2]r[2]...an=l[n]r[n]f(a1,a2...an)[gcd(a1,a2...an)=1]

    转换一下

    ∑ a 1 = l [ 1 ] r [ 1 ] ∑ a 2 = l [ 2 ] r [ 2 ] . . . ∑ a n = l [ n ] r [ n ] f ( a 1 , a 2 . . . a n ) ∗ ε ( g c d ( a 1 , a 2 . . . a n ) = 1 ) \displaystyle\sum_{a_1=l[1]}^{r[1]}\displaystyle\sum_{a_2=l[2]}^{r[2]}...\displaystyle\sum_{a_n=l[n]}^{r[n]}f(a_1,a_2...a_n)*ε(gcd(a_1,a_2...a_n)=1) a1=l[1]r[1]a2=l[2]r[2]...an=l[n]r[n]f(a1,a2...an)ε(gcd(a1,a2...an)=1)

    展开

    ∑ a 1 = l [ 1 ] r [ 1 ] ∑ a 2 = l [ 2 ] r [ 2 ] . . . ∑ a n = l [ n ] r [ n ] f ( a 1 , a 2 . . . a n ) ∗ ∑ d ∣ g c d ( a 1 , a 2 . . . a n ) μ ( d ) \displaystyle\sum_{a_1=l[1]}^{r[1]}\displaystyle\sum_{a_2=l[2]}^{r[2]}...\displaystyle\sum_{a_n=l[n]}^{r[n]}f(a_1,a_2...a_n)*\displaystyle\sum_{d|gcd(a_1,a_2...a_n)}^{}μ(d) a1=l[1]r[1]a2=l[2]r[2]...an=l[n]r[n]f(a1,a2...an)dgcd(a1,a2...an)μ(d)

    交换枚举顺序

    ∑ d = 1 m μ ( d ) ∑ a 1 = l [ 1 ] / d r [ 1 ] / d ∑ a 2 = l [ 2 ] / d r [ 2 ] / d . . . ∑ a n = l [ n ] / d r [ n ] / d f ( a 1 ∗ d , a 2 ∗ d . . . a n ∗ d ) \displaystyle\sum_{d=1}^{m}μ(d)\displaystyle\sum_{a_1=l[1]/d}^{r[1]/d}\displaystyle\sum_{a_2=l[2]/d}^{r[2]/d}...\displaystyle\sum_{a_n=l[n]/d}^{r[n]/d}f(a_1*d,a_2*d...a_n*d) d=1mμ(d)a1=l[1]/dr[1]/da2=l[2]/dr[2]/d...an=l[n]/dr[n]/df(a1d,a2d...and)

    枚举倍数是调和级数,时间复杂度是 O ( l n m ) O(ln m) O(lnm),枚举 n n n个数,那么时间复杂度是 n l n m nlnm nlnm,前面的 d d d枚举起来是 m m m,因此时间复杂度是 O ( n m l n m ) O(nmln m) O(nmlnm)

    #include 
    using namespace std;
    const int N = 500005;
    const int mod = 998244353;
    int check[N + 5], n, m;
    int mu[N + 5], p[N + 5];
    bool flg[N + 5];
    int dp[N];
    int l[N];
    int r[N];
    void mobius()
    {
        int tot = 0;
        mu[1] = 1;
        for (int i = 2; i <= N; ++i)
        {
            if (!flg[i])
            {
                p[++tot] = i;
                mu[i] = -1;
            }
            for (int j = 1; j <= tot && i * p[j] <= N; ++j)
            {
                flg[i * p[j]] = 1;
                if (i % p[j] == 0)
                {
                    mu[i * p[j]] = 0;
                    break;
                }
                mu[i * p[j]] = -mu[i];
            }
        }
    }
    signed main()
    {
        mobius();
        cin >> n >> m;
        for (int i = 1; i <= n; i++)
            cin >> l[i] >> r[i];
        int ans = 0;
    
        for (int d = 1; d <= m; d++)
        {
            if (!mu[d])
                continue;
            int tot = 0;
            int sum = m / d;
            vector<int> dp(sum + 1, 1);
            for (int i = 1; i <= n; i++)
            {
                vector<int> f(sum + 1);
                for (int j = (l[i] + d - 1) / d; j <= sum; j++)
                {
                    f[j] = dp[j - (l[i] + d - 1) / d];
                    if (j >= r[i] / d + 1)
                        f[j] = (f[j] - dp[j - r[i] / d - 1] + mod) % mod;
                }
                dp[0] = 0;
                for (int j = 1; j <= sum; j++)
                    dp[j] = (dp[j - 1] + f[j]) % mod;
            }
            ans = ((ans + dp[sum] * mu[d]) % mod + mod) % mod;
        }
        cout << ans << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
  • 相关阅读:
    2020 CCF非专业级别软件能力认证第一轮(LGR-10)洛谷模拟试题试卷
    TDengine 3.3.0.0 引入图形化管理工具、复合主键等 13 项关键更新
    【报错解决】java:错误:无效的源发行版:15
    斩波稳定(自稳零)精密运算放大器
    迟到的秋招经验分享贴,希望能帮到大家
    Word控件Spire.Doc 【段落处理】教程(十):如何在 C# 中将新段落插入到 Word 文档中
    golang1.21新特性速览
    Python抓取高考网图片
    「C++: Eigen」第一章 第二节 Matrix and vector arithmetic
    VMware与CentOS的安装
  • 原文地址:https://blog.csdn.net/m0_51841071/article/details/126594567