zoukankan      html  css  js  c++  java
  • [CQOI2015]选数

    嘟嘟嘟


    首先问题可以转化一下,变成在([ lceil frac{L}{k} ceil, lfloor frac{R}{k} floor])中选取(n)个数,使这些数的gcd等于1.
    以下的(L)(R)都是除完(k)的。
    但这样做的复杂度是(O(R))的,过不了。
    这时候考虑到一个性质,在这个区间中选取不相同的(n)个数,这(n)个数的gcd一定小于等于他们的极差。
    这样我们的枚举范围就变成了(R - L)
    (dp[i])表示从这个区间中选取不完全相同的(n)个数,他们的gcd = (i)的方案数。
    那么自然有(dp[i] = (frac{R}{i} - frac{L - 1}{i}) ^ n - (frac{R}{i} - frac{L - 1}{i}))
    但是这样(dp[i])也包含了gcd为(2i),(3i)……的情况,所以我们容斥一下,(i)从大到小枚举,把(dp[i])依次减去(dp[2i]),(dp[3i])……。
    有人会问不应该是(dp[i])减去(dp[2i])就行了么。但是别忘了,这时候(dp[2i])已经处理过了,就表示gcd为(2i)的方案数,所以应该减去所有(i)的倍数。
    特殊情况是(L = 1),这时候可以都选(1),所以要加1.

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<stack>
    #include<queue>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 1e5 + 5;
    const ll mod = 1e9 + 7;
    inline ll read()
    {
      ll ans = 0;
      char ch = getchar(), last = ' ';
      while(!isdigit(ch)) last = ch, ch = getchar();
      while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
      if(last == '-') ans = -ans;
      return ans;
    }
    inline void write(ll x)
    {
      if(x < 0) x = -x, putchar('-');
      if(x >= 10) write(x / 10);
      putchar(x % 10 + '0');
    }
    
    In ll quickpow(ll a, ll b)
    {
      ll ret = 1;
      for(; b; b >>= 1, a = a * a % mod)
        if(b & 1) ret = ret * a % mod;
      return ret;
    }
    
    ll dp[maxn];
    
    int main()
    {
      int n = read(), k = read(), L = read(), R = read();
      L = (L + k - 1) / k, R /= k;
      for(int i = 1; i <= R - L; ++i)
        {
          int num = R / i - (L - 1) / i;
          dp[i] = (quickpow(num, n) - num + mod) % mod;
        }
      for(int i = R - L; i; --i)
        for(int j = (i << 1); j <= R - L; j += i) dp[i] = (dp[i] - dp[j] + mod) % mod;
      if(L == 1) dp[1] = (dp[1] + 1) % mod;
      write(dp[1]), enter;
      return 0;
    }
    
  • 相关阅读:
    JavaScript 入门之常见对象
    JavaScript 快速入门
    高级程序设计语言的共性内容
    CSS 快速入门
    HTML 快速入门
    正则表达式
    Oracle 11g安装
    部分框架结构图
    java定时器
    java垃圾回收机制的使用
  • 原文地址:https://www.cnblogs.com/mrclr/p/10416526.html
Copyright © 2011-2022 走看看