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
原文地址:https://www.cnblogs.com/Pneuis/p/15172028.html