• 【BZOJ3309】DZY Loves Math


    题意:

    对于正整数n,定义$f(n)$为$n$所含质因子的最大幂指数。例如$f(1960)=f(2^3 * 5^1 * 7^2)=3$,$f(10007)=1$,$f(1)=0$。
    给定正整数$a,b$,求

    $$sumlimits_{i=1}^{a}sumlimits_{j=1}^{b}f(gcd(i,j))$$

    多组数据,$Tleq 10000$

    $1leq a,bleq 10^7$

    题解:

    还是莫比乌斯反演,设$a<b$:

    $$sumlimits_{i=1}^{a}sumlimits_{j=1}^{b}f(gcd(i,j))$$

    $$=sumlimits_{d=1}^{a}f(d)sumlimits_{k=1}^{lfloorfrac{a}{d} floor}mu(k)lfloorfrac{a}{kd} floorlfloorfrac{b}{kd} floor$$

    $$=sumlimits_{i=1}^{a}lfloorfrac{a}{i} floorlfloorfrac{b}{i} floorsumlimits_{d|i}f(d)mu(frac{i}{d})$$

    设$g(n)=sumlimits_{d|n}f(d)mu(frac{n}{d})$,分析这个函数的性质;

    先将$n$质因数分解,$n=prodlimits_{i=1}^{l}p_i^{a_i}$,设$k=max{a_i}$;

    显然当且仅当$frac{n}{d}$每个质因子次数都不超过1时$mu(frac{n}{d})$才非零,所以$f(d)$的值只能取到$k$或者$k-1$;

    那么可以将所有$a_i$分成两个集合,$A$集合表示取到$k$的,$B$集合表示小于$k$的,显然$g$的取值由$A$中的元素决定;考虑$d$减少了哪些质因数的次数,如果有$A$集合中的元素被选到,则剩下的在$B$集合中的选择奇偶可能性相同;

    根据$mu$的定义可以知道,奇数会产生1的贡献,偶数则会产生-1的贡献,则全部的贡献加起来就为0;

    如果不选$A$中的元素,则对B也类似分成两半来讨论,最终还是会得到0;

    因此只有$a_i$全相等的情况才会产生非零的答案;

    在里面任意选奇数或偶数个方案数依然相等,加起来贡献为0,但是特殊情况是全选时,此时$f$的值为$k-1$(其他情况为$k$),因此要多减去一个1;

    所以此时$g(n)=(-1)^{l+1}$,其他时候$g(n)$均为0;

    记录一下每个数的最小素因子次数和除掉最小素因子的上一个数,就可以线性筛预处理了;

    剩下的数论分块前缀和啥的就是常规操作了吧……

    代码:

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<cmath>
     6 #include<queue>
     7 #define inf 2147483647
     8 #define eps 1e-9
     9 using namespace std;
    10 typedef long long ll;
    11 int T,n,m,pri=0,p[1000001],g[10000001],t[10000001],las[10000001];
    12 bool isp[10000001];
    13 void _(){
    14     for(int i=2;i<=10000000;i++){
    15         if(!isp[i]){
    16             p[++pri]=i;
    17             t[i]=las[i]=g[i]=1;
    18         }
    19         for(int j=1;j<=pri&&i*p[j]<=10000000;j++){
    20             isp[i*p[j]]=true;
    21             if(i%p[j]==0){
    22                 las[i*p[j]]=las[i];
    23                 t[i*p[j]]=t[i]+1;
    24                 if(las[i]==1)g[i*p[j]]=1;
    25                 else if(t[las[i]]==t[i]+1)g[i*p[j]]=-g[las[i]];
    26                 break;
    27             }
    28             las[i*p[j]]=i;
    29             t[i*p[j]]=1;
    30             if(t[i]==1)g[i*p[j]]=-g[i];
    31         }
    32     }
    33     for(int i=1;i<=10000000;i++)g[i]+=g[i-1];
    34 }
    35 ll calc(int n,int m){
    36     ll ret=0;
    37     for(int i=1,las=1;i<=n;i=las+1){
    38         las=min(n/(n/i),m/(m/i));
    39         ret+=(ll)(g[las]-g[i-1])*(n/i)*(m/i);
    40     }
    41     return ret;
    42 }
    43 int main(){
    44     _();
    45     scanf("%d",&T);
    46     while(T--){
    47         scanf("%d%d",&n,&m);
    48         if(n>m)swap(n,m);
    49         printf("%lld
    ",calc(n,m));
    50     }
    51     return 0;
    52 }
  • 相关阅读:
    一条SQL的执行流程
    LinkedList源码解析
    MinorGC前检查
    AbstractList源码分析
    JVM常用命令
    CountDownLatch源码解析
    ReentrantLock源码解析
    HTTPS简单介绍
    工厂方法模式
    观察者模式
  • 原文地址:https://www.cnblogs.com/dcdcbigbig/p/10107467.html
Copyright © 2020-2023  润新知