zoukankan      html  css  js  c++  java
  • CF1559E -Mocha and Stars (dp+莫比乌斯反演)

    题目

    给定n个区间[l_i,r_i]和数m,问有多少组(a_1,a_2,...,a_i)满足:

    • (a_iin [l_i,r_i])
    • (sumlimits_{i=1}^na_ile m)
    • (gcd(a_1,...,a_n)=1)

    数据范围:(nle 50)(m le 10^5)

    题解

    先想想不考虑(gcd)的限制的情况下怎么做。就是一个简单的(dp)(dp[i][j])代表前(i)个区间总和为j的方案数。

    [dp[i][j]=sumlimits_{k=j-r_i}^{j-l_i}{dp[i-1][k]} ]

    时间复杂度为(O(ncdot m))(m)为最大值。

    然后就是经典的莫比乌斯反演

    [egin{aligned} ans&=sumlimits_{x_1=1}^{[l_1,r_1]}{sumlimits_{x_2=1}^{[l_2,r_2]}{...sumlimits_{x_n=1}^{[l_n,r_n]}{[x_1+...+x_nleq m]cdot [gcd(x_1,...,x_n)]}}} \ &=sumlimits_{x_1=1}^{[l_1,r_1]}{sumlimits_{x_2=1}^{[l_2,r_2]}{...sumlimits_{x_n=1}^{[l_n,r_n]}{[x_1+...+x_nleq m]cdot sumlimits_{d|x_1,d|x_2,...,d|x_n}{mu(d)}}}} \ &=sum_{d=1}^{m}{mu(d)(sumlimits_{x_1=1}^{[frac{l_1}{d},frac{r_1}{d}]}{sumlimits_{x_2=1}^{[frac{l_2}{d},frac{r_2}{d}]}{...sumlimits_{x_n=1}^{[frac{l_n}{d},frac{r_n}{d}]}{[x_1+...+x_nleq frac{m}{d}]}}})} end{aligned} ]

    后面括号那一坨就是前面的(dp)可以解决。

    #include <bits/stdc++.h>
    
    #define endl '
    '
    #define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
    #define mp make_pair
    #define seteps(N) fixed << setprecision(N) 
    typedef long long ll;
    
    using namespace std;
    /*-----------------------------------------------------------------*/
    
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    #define INF 0x3f3f3f3f
    
    const int N = 3e5 + 10;
    const int M = 998244353;
    const double eps = 1e-5;
    int rev[N];
    
    typedef pair<int, int> PII;
    PII seg[N];
    int cnt;
    int prime[N];
    int isnp[N];
    int mu[N];
    ll dp[60][N];
    
    ll solve(int p, int n, int m) {
        int mx = m / p;
        for(int i = 0; i <= mx; i++) {
            dp[0][i] = 1;
        }
        for(int i = 1; i <= n; i++) {
            bool flag = true;
            int l = seg[i].first / p + (seg[i].first % p != 0), r = seg[i].second / p;
            if(l > r) return 0;
            for(int j = 1; j <= mx; j++) {
                dp[i][j] = ((j - l < 0 ? 0 : dp[i - 1][j - l]) - (j - r - 1 < 0 ? 0 : dp[i - 1][j - r - 1]) + M) % M;
                dp[i][j] = (dp[i][j] + dp[i][j - 1]) % M;
            }
        }
        return dp[n][mx];
    }
    
    
    int main() {
        int n, m;
        mu[1] = 1;
        isnp[1] = 1;
        prime[0] = 1;
        for(int i = 2; i < N; i++) {
            if(!isnp[i]) {
                prime[++cnt] = i;
                mu[i] = -1;
            }
            for(int j = 1; j <= cnt && i * prime[j] < N; j++) {
                isnp[i * prime[j]] = 1;
                if(i % prime[j] == 0) {
                    mu[i * prime[j]] = 0;
                    break;
                }
                mu[i * prime[j]] = -mu[i];
            }
        }
        cin >> n >> m;
        for(int i = 1; i <= n; i++) {
            cin >> seg[i].first >> seg[i].second;
        }
        ll ans = 0;
        for(int i = 1; i <= m; i++) {
            if(!mu[i]) continue;
            ans += mu[i] * solve(i, n, m);
            ans %= M;
        }
        cout << (ans + M) % M << endl;
    }
    
  • 相关阅读:
    bzoj 1176 cdq分治套树状数组
    Codeforces 669E cdq分治
    Codeforces 1101D 点分治
    Codeforces 1100E 拓扑排序
    Codeforces 1188D Make Equal DP
    Codeforces 1188A 构造
    Codeforces 1188B 式子转化
    Codeforces 1188C DP 鸽巢原理
    Codeforces 1179D 树形DP 斜率优化
    git commit -m "XX"报错 pre -commit hook failed (add --no-verify to bypass)问题
  • 原文地址:https://www.cnblogs.com/limil/p/15172011.html
Copyright © 2011-2022 走看看