• Codeforces


    题意:

      给出n个数的范围 l和 ri。从每个范围中各选择出一个数,使得n个数的总和不大于m,且公共gcd值为1。求方案数。

    题解:

      从1到m,dp出每个数作为gcd值且总和不大于m的情况。

      枚举当前的gcd值为d,那么最多有m/d份这样的值。

      f[i][j]代表第i个范围使用d的数量不大于j时的情况数,使用滚动数组优化掉一维。

      但是最终求出的每个值作为gcd的方案数还要再容斥一下,因为对于某个值x作为gcd的方案数,其实还包含2x,3x...这样的情况。

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e5+10;
    const int mod = 998244353;
    int n, m;
    int l[55], r[55];
    int g[N];
    int f[N], dp[N];
    
    int get(int x) {
        return x < 0 ? 0 : dp[x];
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++)
            scanf("%d%d", &l[i], &r[i]);
    
        for(int d = m; d >= 1; d--) {
            int t = m / d;
            for(int i = 0; i <= t; i++)
                dp[i] = 1;
    
            for(int i = 1; i <= n; i++) {
                int L = (l[i] + d - 1) / d;
                int R = r[i] / d + 1;
                for(int j = 1; j <= t; j++) 
                    f[j] = ((f[j-1] + get(j-L)) % mod - get(j-R) + mod) % mod;
                
                for(int j = 0; j <= t; j++)
                    dp[j] = f[j];
            }
            g[d] = dp[t];
        }
    
        for(int d = m; d >= 1; d--) {
            for(int i = 2; i * d <= m; i++)
                g[d] = (g[d] - g[i*d] + mod) % mod;
        }
        printf("%d
    ", g[1]);
    }
    C++
    package main
    import (
        "io"
        "os"
        "fmt"
        "bufio"
    )
    const N int = 1e5+10
    const mod int = 998244353
    var n, m int
    var l, r [55]int
    var g, f, dp [N]int
    
    func get(x int) int {
        if x < 0 {
            return 0
        } else {
            return dp[x]
        }
    }
    
    func main() {
        var input io.Reader = bufio.NewReader(os.Stdin)
        fmt.Fscan(input, &n)
        fmt.Fscan(input, &m)
        for i := 1; i <= n; i++ {
            fmt.Fscan(input, &l[i])
            fmt.Fscan(input, &r[i])
        }
    
        for d := m; d >= 1; d-- {
            t := m / d
            for i := 0; i <= t; i++ {
                dp[i] = 1
            }
            for i := 1; i <= n; i++ {
                L := (l[i] + d - 1) / d
                R := r[i] / d + 1
                for j := 1; j <= t; j++ {
                    f[j] = ((f[j-1] + get(j-L)) % mod - get(j-R) + mod) % mod
                }
                for j := 0; j <= t; j++ {
                    dp[j] = f[j]
                }
            }
            g[d] = dp[t]
        }
    
        for d := m; d >= 1; d-- {
            for i := 2; i * d <= m; i++ {
                g[d] = (g[d] - g[i*d] + mod) % mod
            }
        }
        fmt.Print(g[1])
    }
    Go
  • 相关阅读:
    POJ 1754 Splay
    POJ 3481Double Queue Splay
    前缀表达式求值
    Treap(树堆):随机平衡二叉树实现
    Tarjian算法求强联通分量
    (转)priority_queue的用法
    001Angular2环境准备
    9.富客户端应用程序的线程
    8.信号
    7.线程的优先级
  • 原文地址:https://www.cnblogs.com/Pneuis/p/15172028.html
Copyright © 2020-2023  润新知