zoukankan      html  css  js  c++  java
  • 【2017多校训练08 1002】【HDOJ 6134】Battlestation Operational

    典型的数列反演题。

    运用莫比乌斯反演的一个结论 $[n = 1] = sum_{d | n} mu(d)$,将表达式做如下转化:

    $$ ans = sum_{i=1}^n sum_{j=1}^i (lfloor frac{i-1}{j} floor + 1) sum_{d | i land d | j} mu(d) \ = sum_{d=1}^n mu(d) sum_{i=1}^{lfloor frac{n}{d} floor} sum_{j=1}^i (lfloor frac{i-1}{j} floor + 1) $$

    令$$F_n = sum_{i=1}^n sum_{j=1}^i (lfloor frac{i-1}{j} floor + 1)$$

    则有$$ans = sum_{d=1}^n mu(d) F(lfloor frac{n}{d} floor)$$

    先考虑如何计算Fn.

    观察得知,内层求和与n无直接关联,不妨直接对F相邻两项做差:

    $$dF_n = F_n - F_{n-1} \= sum_{j=1}^n (lfloor frac{n-1}{j} floor + 1) $$

    考虑每个j对每个n的贡献。

    对于一个给定的j,我们可以枚举$lfloor frac{n-1}{j} floor$的取值t,此时j和t将对$[j*t+1, j*(t+1)+1)$这一范围内所有的n对应的$F_n$产生t+1的贡献。

    由调和级数可知,对所有j枚举它们在N以内的倍数只需要O(Nlog(N))级别的时间复杂度。我们只要在枚举j和t的同时维护一下$dF_n$的相邻两项差,最后做两次前缀和就可以得到$F_n$数列了。

    再来考虑如何由$F_n$计算$ans_n$。

    由$ans_n = sum_{d=1}^n mu(d) F(lfloor frac{n}{d} floor)$,与上一步类似,同样可以考虑每个d对每个n的答案的贡献。对于每个d,枚举$lfloor frac{n}{d} floor$的取值t,此时d和t对$[t*d, (t+1)*d)$范围内所有的n对应的$ans_n$产生$mu(d) * F_t$ 的贡献。枚举结束后再做一遍前缀和即可。

     1 #include <iostream>
     2 #include <cmath>
     3 #include <cstdio>
     4 #include <algorithm>
     5 using namespace std;
     6 const int maxn = 1000005, mod = 1000000007;
     7 typedef long long LL;
     8 int mu[maxn], muS[maxn], F[maxn], ans[maxn], P[maxn], pcnt, N;
     9 bool not_p[maxn];
    10 
    11 void sieve()
    12 {
    13     mu[1] = 1;
    14     for(int i = 2;i < maxn;++i)
    15     {
    16         if(!not_p[i]) P[pcnt++] = i, mu[i] = -1;
    17         for(int j = 0;j < pcnt;++j)
    18         {
    19             if(i * P[j] >= maxn) break;
    20             not_p[i * P[j]] = true;
    21             if(i % P[j] == 0)
    22             {
    23                 mu[i * P[j]] = 0;
    24                 break;
    25             }
    26             else mu[i * P[j]] = -mu[i];
    27         }
    28     }
    29 }
    30 
    31 void init()
    32 {
    33     sieve();
    34     for(int i = 2;i <= N;++i) muS[i] = muS[i-1] + mu[i];
    35     N = 1000000;
    36     int L, R;
    37     for(int k = 1;k < N;++k)
    38     {
    39         L = k, R = k+k;
    40         for(int t = 1;L < N;++t, L += k, R += k)
    41         {
    42             F[L+1] = (F[L+1] + t) % mod;
    43             if(R < N) F[R+1] = (F[R+1] - t) % mod;
    44             //if(L < 3) printf("k = %d, (%d, %d] = %d
    ", k, L, N, t);
    45         }
    46     }
    47     for(int i = 2;i <= N;++i) F[i] = (F[i] + F[i-1]) % mod;
    48     for(int i = 2;i <= N;++i) F[i] = (F[i] + F[i-1]) % mod;
    49     for(int i = 1;i <= N;++i)
    50         F[i] = (F[i] + (LL) i * (i+1) / 2) % mod;
    51     for(int i = 1;i <= N;++i) //F[d]
    52     {
    53         for(int j = 1, k = i;k <= N;++j, k += i)
    54         {
    55             int tmp = (mod + F[j] * mu[i]) % mod;
    56             ans[k] = (ans[k] + tmp) % mod;
    57             if(k+i <= N) ans[k+i] = (ans[k+i] + mod - tmp) % mod;
    58         }
    59     }
    60     for(int i = 2;i <= N;++i) ans[i] = (ans[i] + ans[i-1]) % mod;
    61 }
    62 
    63 void work()
    64 {
    65     while(~scanf("%d", &N))
    66     {
    67         printf("%d
    ", ans[N]);
    68     }
    69 }
    70 int main() {
    71     // your code goes here
    72     int T;
    73     init();
    74     work();
    75     return 0;
    76 }
    莫比乌斯函数,差分数列
  • 相关阅读:
    数据对齐
    算法面试题集——从各大博客收集
    软件工程师规划
    链栈,顺序栈,单链队列,循环队列,非循环队列的简单实现
    C,C++文件和目录操作的一些整理
    WPF使用笔记-计时器,多线程更新界面,焦点移动等
    Heap Data Structure and Heap Sort
    YUV420P像素数据编码为JPEG图片
    根据txt文件中指定的文件名进行文件分类
    MFC显示图片和写入文件
  • 原文地址:https://www.cnblogs.com/Asm-Definer/p/7397951.html
Copyright © 2011-2022 走看看