• P2522 [HAOI2011]Problem b


    P2522 [HAOI2011]Problem b(我的第一道莫比乌斯反演)

     题解:

    根据题意写出函数表达式:

    (fleft ( k ight )=sum_{i=1}^{n}sum_{j=1}^{m}left [ gcdleft ( i,j ight)=k ight ])  表示(1leq ileq n,1leq jleq m) , (gcdleft ( i,j ight)=k)成立的(left ( i,j ight ))对数

    令(Fleft ( x ight )=sum_{x|d}fleft ( d ight )),代表 (gcd=d且是x的倍数的left ( i,j ight )对数);

    我们知道(x|gcdleft ( i,j ight)=left ( x|i ight )wedge left ( x|j ight )),又因为(1sim n之间整除x的数有left lfloor frac{n}{x} ight floor个),(1sim m之间整除x的数有left lfloor frac{m}{x} ight floor个)

    所以(Fleft ( x ight )=left lfloor frac{n}{x} ight floorcdot left lfloor frac{m}{x} ight floor)

    于是:((Fleft ( x ight )=sum_{x|d}^{d}=left lfloor frac{n}{x} ight floorcdot left lfloor frac{m}{x} ight floor)

    根据第二种莫比乌斯反演:则(fleft ( x ight )=sum_{x|d}mu left ( frac{d}{x} ight )Fleft ( d ight ))

    带入(Fleft ( d ight )=left lfloor frac{n}{d} ight floorcdot left lfloor frac{m}{d} ight floor) 得

    (fleft ( x ight )=sum_{x|d}mu left ( frac{d}{x} ight )left lfloor frac{n}{d} ight floorleft lfloor frac{m}{d} ight floor)

    此时(x=d),(dleq minleft ( n,m ight )),则(fleft ( x ight )=sum_{d=1}^{minleft ( n,m ight )}mu left ( frac{d}{x} ight )left lfloor frac{n}{d} ight floorleft lfloor frac{m}{d} ight floor)

    令(t=frac{d}{x}),则(d=xt);(dleq minleft ( n,m ight )),则(t=frac{d}{x}leq minleft ( frac{n}{x},frac{m}{x} ight ))

    于是:(fleft ( d ight )=sum_{t=1}^{minleft ( frac{n}{d},frac{m}{d} ight )}mu left ( t ight )left lfloor frac{n}{td} ight floorleft lfloor frac{m}{td} ight floor)

    (d)是题目所给的常数,这里是(k);

    注意题目不是(1leq ileq b,1leq jleq d),所以还要用到容斥原理,算出(1sim b,1sim d),减去(1sim a,1sim d),再减去(1sim c,1sim b),再加上(1sim a,1sim c)

    整除分块+前缀和(预处理莫比乌斯函数)

    AC_Code:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 typedef unsigned long long ull;
     5 const int maxn = 5e4+10;
     6 const int mod = 2333333;
     7 const int inf = 0x3f3f3f3f;
     8 #define gok ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
     9 #define pii pair<int,int>
    10 #define fi first
    11 #define se second
    12 #define pb push_back
    13 #define rep(i,first,second) for(ll i=first;i<=second;i++)
    14 #define dep(i,first,second) for(ll i=first;i>=second;i--)
    15 #define erep(i,u) for(ll i=head[u];~i;i=e[i].nxt)
    16 
    17 int a,b,c,d,k;
    18 bool prime[maxn];
    19 int Prime[maxn],tot,mu[maxn],sum[maxn];
    20 void get_mu(){
    21     memset(prime,true,sizeof(prime));
    22     prime[0]=prime[1]=false;
    23     mu[1]=1;
    24     for(int i=2;i<=50000;i++){
    25         if( prime[i] ) Prime[++tot]=i,mu[i]=-1;
    26         for(int j=1;j<=tot&&i*Prime[j]<=50000;j++){
    27             prime[i*Prime[j]]=false;
    28             if( i%Prime[j]==0 ){
    29                 mu[i*Prime[j]]=0;
    30                 break;
    31             }
    32             mu[i*Prime[j]]=-mu[i];
    33         }
    34     }
    35     for(int i=1;i<=50000;i++) sum[i]=sum[i-1]+mu[i];
    36 }
    37 
    38 int cal(int n,int m){
    39     int res=0;
    40     for(int i=1,j;i<=min(n,m);i=j+1){
    41         j=min(n/(n/i),m/(m/i));
    42         res += (sum[j]-sum[i-1])*(n/i)*(m/i);
    43     }
    44     return res;
    45 }
    46 
    47 int main()
    48 {
    49     int t;
    50     scanf("%d",&t);
    51     get_mu();
    52 //    rep(i,1,10) cout<<mu[i]<<' '<<sum[i]<<endl;
    53     while( t-- ){
    54         scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
    55         printf("%d
    ",cal(b/k,d/k)-
    56                cal((a-1)/k,d/k)-
    57                cal(b/k,(c-1)/k)+
    58                cal((a-1)/k,(c-1)/k));
    59     }
    60     return 0;
    61 }

     再放一道例题:注意下边界都是从1开始,且(a,b)(b,a)算一种,注意去重

    AC_Code:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <string>
     6 using namespace std;
     7 typedef long long ll;
     8 const int maxn = 1e5+10;
     9 const int mod = 1e9+7;
    10 const int inf = 0x3f3f3f3f;
    11 #define rep(i,first,second) for(ll i=first;i<=second;i++)
    12 #define dep(i,first,second) for(ll i=first;i>=second;i--)
    13 
    14 bool prime[maxn];
    15 ll Prime[maxn],tot,mu[maxn];
    16 ll ans,sum[maxn];
    17 ll a,b,c,d,k;
    18 
    19 void get_mu(){
    20     memset(prime,true,sizeof(prime));
    21     prime[0]=prime[1]=false;
    22     mu[1]=1;
    23     rep(i,2,100000){
    24         if( prime[i] ) Prime[++tot]=i,mu[i]=-1;
    25         for(ll j=1;j<=tot&&i*Prime[j]<=100000;j++){
    26             prime[i*Prime[j]]=false;
    27             if( i%Prime[j]==0 ){
    28                 mu[i*Prime[j]]=0;
    29                 break;
    30             }
    31             mu[i*Prime[j]]=-mu[i];
    32         }
    33     }
    34     rep(i,1,100000) sum[i]=sum[i-1]+mu[i];
    35 }
    36 
    37 ll cal(ll x,ll y){
    38     ll up=min(x,y);
    39     ll res=0;
    40     for(ll i=1,j;i<=up;i=j+1){
    41         j=min(x/(x/i),y/(y/i));
    42         res += (sum[j]-sum[i-1])*(x/i)*(y/i);
    43     }
    44     return res;
    45 }
    46 
    47 int main()
    48 {
    49     int t,cas=0;
    50     scanf("%d",&t);
    51     get_mu();
    52     while( t-- ){
    53         scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&k);
    54         if( k==0 ){
    55             printf("Case %d: 0
    ",++cas);
    56             continue;
    57         }
    58         b=b/k;d=d/k;
    59         ll up=min(b,d);
    60         ll ans1=cal(b,d);//重复区有两倍,要减去一倍
    61         ll ans2=cal(up,up);//重复区的那两倍数算出来
    62         printf("Case %d: %lld
    ",++cas,ans1-ans2/2);//重复区的那两倍减去其中一倍即可
    63     }
    64     return 0;
    65 }
  • 相关阅读:
    aodquery,clientdataset数据控件之间的速度区别
    centos防火墙相关
    centos安装jdk,精简
    delphi 操作excel复制区域功能呢
    centos安装redis,最靠谱的教程
    图像识别,借助百度云,上传图片实现逻辑
    LinkedHashmap和HashMap对比以及说明
    Windows环境下Zookeeper安装和使用
    你不知道的JavaScript--Item1 严格模式
    jQuery学习之旅 Item2 选择器【二】
  • 原文地址:https://www.cnblogs.com/wsy107316/p/12786328.html
Copyright © 2020-2023  润新知