zoukankan      html  css  js  c++  java
  • [POI2007]ZAP-Queries && [HAOI2011]Problem b 莫比乌斯反演

    1,[POI2007]ZAP-Queries

    ~~~题面~~~
    题解: 首先列出式子:$$ans = sum_{i = 1}^{n}sum_{j = 1}^{m}[gcd(i, j) == d]$$
        $$[gcd(i, j) == d] = [gcd(lfloor{frac{i}{d}} floor,lfloor{frac{j}{d}} floor) == 1]$$
        所以原式 $$Rightarrow quad sum_{i = 1}^{lfloor{frac{n}{d}} floor}sum_{j = 1}^{lfloor{frac{m}{d}} floor}[gcd(i, j)==1]$$
        $$Rightarrow quad sum_{i = 1}^{n}sum_{j = 1}^{m}sum_{d|gcd(i, j)}mu(d)$$
        因为$mu(d)$会被统计到当且仅当$d | i quad and quad d | j$,即$d | gcd(i, j)$
        那么考虑将满足条件的i和j两两搭配,组成的方案数就是$mu(d)$会被统计到的次数,
        也就是$mu(d)$会被统计到$lfloor{frac{n}{d}} floorlfloor{frac{m}{d}} floor$次
        $$Rightarrow quad ans=sum_{i=1}^{min(n,m)}{mu(d)lfloor{frac{n}{d}} floorlfloor{frac{m}{d}} floor}$$
        然后观察到$lfloor{frac{n}{d}} floorlfloor{frac{m}{d}} floor$中有很多小段$lfloor{frac{n}{d}} floorlfloor{frac{m}{d}} floor$乘积是固定的,也就是$lfloor{frac{n}{d}} floor$和$lfloor{frac{m}{d}} floor$同时为一个固定的值,因此我们可以用整数分块优化

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define R register int
     4 #define AC 55000
     5 int t, n, m, d;
     6 int prime[AC], mu[AC], sum[AC], tot;
     7 bool z[AC];
     8 
     9 inline int read()
    10 {
    11     int x = 0;char c = getchar();
    12     while(c > '9' || c < '0') c = getchar();
    13     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    14     return x;
    15 }
    16 
    17 void getprime()
    18 {
    19     int now;
    20     mu[1] = 1;
    21     for(R i = 2; i <= 50000; i++)
    22     {
    23         if(!z[i]) prime[++tot] = i, mu[i] = -1;
    24         for(R j = 1; j <= tot; j++)
    25         {
    26             now = prime[j];
    27             if(now * i > 50000) break;
    28         //    printf("!!!%d %d
    ", now, i);
    29             z[now * i] = true;
    30             if(!(i % now)) break;
    31             mu[i * now] = -mu[i];
    32         }
    33     }
    34     for(R i = 1; i <= 50000; i++) 
    35         sum[i] = mu[i] + sum[i - 1];
    36 }
    37 
    38 int ans;
    39 
    40 void work()
    41 {
    42     int pos;
    43     t = read();
    44     for(R i = 1; i <= t; i++)
    45     {
    46         n = read(), m = read(), d = read();
    47         n /= d, m /= d;
    48         int b = min(n, m);
    49         ans = 0;
    50         for(R j = 1; j <= b; j = pos + 1)
    51         {
    52             pos = min(n / (n / j), m / (m / j));
    53             ans += (sum[pos] - sum[j-1]) * (n / j) * (m / j);            
    54         }   
    55         printf("%d
    ", ans);
    56     }
    57 }
    58 
    59 int main()
    60 {
    61 //    freopen("in.in", "r", stdin);
    62     getprime();
    63     work();
    64 //    fclose(stdin);
    65     return 0;
    66 }
    View Code


    2,[HAOI2011]Problem b

    ~~~题面~~~
    题解: 这题相比上题多出了两个限制条件,同时对上下限都有限制,那么此时可以用一个容斥来求。
        设$cal(n,m)$表示满足$x le n$和$y le m$且$gcd(x, y) = d$的点对个数,
        那么$$ans = cal(b, d) - cal(a - 1, d) - cal(b, c - 1) + cal(a - 1, c - 1);$$

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define R register int
     4 #define AC 55000
     5 #define LL long long
     6 int a, b, c, d, tot, k, t, ans;
     7 int prime[AC], mu[AC], sum[AC];
     8 bool z[AC];
     9 
    10 inline int read()
    11 {
    12     int x = 0; char c = getchar();
    13     while(c > '9' || c < '0') c = getchar();
    14     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    15     return x;
    16 }
    17 
    18 void pre()
    19 {
    20     int now;
    21     mu[1] = 1;
    22     for(R i = 2; i <= 50000; i++)
    23     {
    24         if(!z[i]) prime[++tot] = i, mu[i] = -1;//质数的mu值肯定都是-1
    25         for(R j = 1; j <= tot; j++)
    26         {
    27             now = prime[j];
    28             if(now * i > 50000) break;
    29             z[now * i] = true;
    30             if(!(i % now)) break;
    31             mu[i * now] = -mu[i];//error这里的mu是由mu[i]得来的啊!!!
    32         }
    33     }
    34     for(R i = 1; i <= 50000; i++) sum[i] = sum[i - 1] + mu[i];
    35 }
    36 
    37 int cal(int n, int m)
    38 {
    39     n /= k, m /= k;
    40     int b = min(n, m), pos, rnt = 0;
    41     for(R i = 1; i <= b; i = pos + 1)
    42     {
    43         pos = min(n / (n / i), m / (m / i));
    44         rnt += (sum[pos] - sum[i-1]) * (n / i) * (m / i);
    45     }
    46     return rnt;
    47 }
    48 //ans = cal(b, d) - cal(a - 1, d) - cal(b, c - 1) + cal(a - 1 , c - 1),相当于容斥 
    49 
    50 void work()
    51 {
    52     t = read();
    53     for(R i = 1; i <= t; i++)
    54     {
    55         a = read(), b = read(), c = read(), d = read(), k = read();
    56         ans = cal(b, d) - cal(a - 1, d) - cal(b, c - 1) + cal(a - 1, c - 1);
    57         printf("%d
    ", ans);
    58     }
    59 }
    60 
    61 int main()
    62 {
    63 //    freopen("in.in", "r", stdin);
    64     pre();
    65     work();
    66 //    fclose(stdin);
    67     return 0;
    68 }
    View Code
  • 相关阅读:
    Erlang学习记录:转义
    Erlang学习记录:运算符
    Erlang学习记录:语法和特性
    Erlang学习记录:相关工具和文档
    IDEA快捷键(收集自网络后整理)
    Redis学习
    SQL_server_2008_r2和visual studio 2010旗舰版的安装(2013-01-16-bd 写的日志迁移
    oracle 11gR2 for win7旗舰版64安装以及连接plsql和NaviCat(win64_11gR2_database) (2012-12-31-bd 写的日志迁移
    win7在某个盘或文件夹中出现右键只能新建文件夹的情况 (2012-12-28-bd 写的日志迁移
    宏基笔记本升级bios(2012-12-28-bd 写的日志迁移
  • 原文地址:https://www.cnblogs.com/ww3113306/p/9471558.html
Copyright © 2011-2022 走看看