zoukankan      html  css  js  c++  java
  • [SDOI2014]数表 莫比乌斯反演

    ~~~题面~~~

    题解:

    设$f(d)$表示数$d$的约数和,那么$(i, j)$中的数为$f(gcd(i, j))$,
    那么有2种枚举方法。
    1,枚举每一格看对应的$f(d)$是几.$$ans = sum_{i = 1}^{n}sum_{j = 1}^{m}{f(gcd(i, j))}$$
    2,枚举$d$看有哪些格子的$f$值为$f(d)$.
    $$ans = sum_{i = 1}^{min(n, m)}{f(d)}sum_{x = 1}^{n}sum_{y = 1}^{m}[gcd(x, y) == d]$$
    显然后者更加方便。
    所以$$ans = sum_{i = 1}^{min(n, m)}{f(d)}sum_{x = 1}^{n}sum_{y = 1}^{m}[gcd(x, y) == d]$$
    $$ans = sum_{i = 1}^{min(n, m)}{f(d)}sum_{x = 1}^{lfloor{frac{n}{d}} floor}sum_{y = 1}^{lfloor{frac{m}{d}} floor}[gcd(x, y) == 1]$$
    $$ans = sum_{i = 1}^{min(n, m)}{f(d)}sum_{x = 1}^{lfloor{frac{n}{d}} floor}sum_{y = 1}^{lfloor{frac{m}{d}} floor}sum_{t | gcd(x, y)}{mu(t)}$$
    $$sum_{i = 1}^{min(n, m)}f(d)sum_{t = 1}^{min(lfloor{frac{n}{d}} floor, lfloor{frac{m}{d}} floor)}{lfloor{frac{lfloor{frac{n}{d}} floor}{t}} floor}{lfloor{frac{lfloor{frac{m}{d}} floor}{t}} floor}mu(t)$$<---看有多少对$(x, y)$统计到了$mu(t)$(即为$mu(t)$的倍数/有因子$mu(t)$)
    $$sum_{i = 1}^{min(n, m)}f(d)sum_{t =1}^{min(lfloor{frac{n}{d}} floor, lfloor{frac{m}{d}} floor)}{lfloor{frac{n}{td} floor}}{lfloor{frac{m}{td} floor}}mu(t)$$
    令$T = td$,则
    $$ans = sum_{T = 1}^{min(n, m)}{lfloor{frac{n}{T}} floor lfloor{frac{m}{T}} floor} sum_{d|T}f(d)mu(frac{T}{d})$$
    因为$T = td$,所以符合要求的$d$满足$d|T$.
    设$$g(T) = sum_{d | T}f(d)mu(frac{T}{d}) Longleftrightarrow f(T) = sum_{d | T}g(d)$$
    $$ans = sum_{T = 1}^{min(n, m)}{lfloor{frac{n}{T}} floor lfloor{frac{m}{T}} floor} g(T)$$
    但是由于有$a$的限制,对于不同的$a$,$g(T)$的值是不同的,因此先筛出$f$数组,然后将$f$按$f_{i}$排序,离线询问,一个一个把符合条件的$f(d)$加入$g$数组,也就是每次处理询问时再暴力将$f(d)$的贡献加给满足$d|T$的$g(T)$,但是由于要维护$g$数组的前缀和,因此用树状数组维护$g$数组
    根据$f$数组的定义,
    当$xquad mod quad p_{i} quad != quad 0$有$f(x cdot P_{i}) = f(x) + f(x) cdot P_{i}$,其中$P_{i}$是质数
    否则有$f(x cdot p_{i}) = f(x) cdot p_{i} + f(t)$,其中$t$为$x$除去质因数$p_{i}$后的值

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define R register int
      4 #define AC 101000
      5 #define ac 100000
      6 #define LL long long 
      7 #define p 2147483648LL
      8 int t, tot, l;
      9 int prime[AC], mu[AC];
     10 LL g[AC];
     11 bool z[AC];
     12 struct node{
     13     int n, m, a, id;LL ans;
     14 }s[AC];
     15 struct kkk{
     16     int d;
     17     LL w;
     18 }f[AC];
     19 
     20 inline int read()
     21 {
     22     int x = 0;char c = getchar();
     23     while(c > '9' || c < '0') c = getchar();
     24     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
     25     return x;
     26 }
     27 
     28 inline bool cmp(node a, node b)
     29 {
     30     return a.a < b.a;
     31 }
     32 
     33 inline bool cmp1(kkk a, kkk b)
     34 {
     35     return a.w < b.w;
     36 }
     37 
     38 inline int lowbit(int x)
     39 {
     40     return x & (-x);
     41 }
     42 
     43 inline void add(int x, int S)
     44 {
     45 //    if(x <= 4)printf("add %d : %d
    ", x, S);
     46     for(R i = x; i <= ac; i += lowbit(i)) g[i] += S;
     47 }
     48 
     49 inline LL find(int x)
     50 {
     51     LL rnt = 0;
     52     for(R i = x; i; i -= lowbit(i)) rnt += g[i];
     53     return rnt;
     54 }
     55 
     56 void pre()
     57 {
     58     t = read();
     59     for(R i = 1; i <= t; i++)
     60         s[i].n = read(), s[i].m = read(), s[i].a = read(), s[i].id = i;
     61     sort(s + 1, s + t + 1, cmp);
     62 }
     63 
     64 void get()
     65 {
     66     int x;
     67     f[1] =(kkk){1, 1}, mu[1] = 1;
     68     for(R i = 2; i <= ac; i++)
     69     {
     70         f[i].d = i;
     71         if(!z[i]) prime[++tot] = i, f[i].w = i + 1, mu[i] = -1;
     72         for(R j = 1; j <= tot; j++)
     73         {
     74             x = prime[j];
     75             if(x * i > ac) break;
     76             z[x * i] = true;
     77             if(!(i % x)) 
     78             {
     79                 int t = i;
     80                 while(!(t % x)) t /= x;
     81                 f[x * i].w = f[t].w + f[i].w * x; 
     82                 break; 
     83             }
     84             mu[x * i] = -mu[i];
     85             f[x * i].w = f[i].w + f[i].w * x;
     86         }
     87     }
     88     sort(f + 1, f + ac + 1, cmp1);
     89 }
     90 
     91 void build(int a)//更新树状数组
     92 {
     93     for(R i = l + 1; i <= ac; i++)
     94     {
     95         if(f[i].w > a) return ;
     96         ++l;
     97         for(R j = f[i].d; j <= ac; j += f[i].d)
     98             add(j, f[i].w * mu[j / f[i].d]);
     99     }
    100 }
    101 
    102 inline bool cmp2(node a, node b)
    103 {
    104     return a.id < b.id;
    105 }
    106 
    107 void work()
    108 {
    109     for(R i = 1; i <= t; i++)
    110     {
    111         build(s[i].a);
    112         int b = min(s[i].n, s[i].m), pos;
    113         for(R j = 1; j <= b; j = pos + 1)
    114         {
    115             pos = min(s[i].n / (s[i].n / j), s[i].m / (s[i].m / j));
    116             s[i].ans += (s[i].n / j) * (s[i].m / j) * (find(pos) - find(j - 1));
    117             s[i].ans = (s[i].ans + p) % p;//取模error!!!取模的时候记得+p....
    118         }//error!!!无论何时都要+p并取模,,因为可能前面取模后再减就变负数了。。。。加个判断就应对不了负数的情况了
    119     //    printf("
    ");
    120     }
    121     sort(s + 1, s + t + 1, cmp2);
    122     for(R i = 1; i <= t; i++) printf("%lld
    ", s[i].ans);
    123 }
    124 
    125 int main()
    126 {
    127     freopen("in.in", "r", stdin);
    128     //freopen("sdoi2014shb.in", "r", stdin);
    129     //freopen("sdoi2014shb.out", "w", stdout);
    130     pre();
    131     get();
    132     work();
    133     fclose(stdin);
    134     //fclose(stdout);
    135     return 0;
    136 }
  • 相关阅读:
    Windows抓屏技术
    几种常见的跨域技术
    实现圆角的3种方式
    svg基础
    nodejs基础(二)
    nodejs的基础(1)
    css3一些常见样式的兼容性处理
    JS中Array的使用
    浏览器的几种模式
    XHR2通信基础
  • 原文地址:https://www.cnblogs.com/ww3113306/p/9488799.html
Copyright © 2011-2022 走看看