• ACM-ICPC 2018 南京赛区网络预赛Sum,线性筛处理积性函数


    SUM

      题意:f(n)是n可以拆成多少组n=a*b,a和b都是不包含平方因子的方案数目,对于a!=b,n=a*b和n=b*a算两种方案,求i=1nf(i)

      首先我们可以知道,n=1时f(1)=1,

      然后我们继续分析,当n为素数p时,只能拆成n=1*p和n=p*1这两种,所以f(p)=2,

      而当n=两个质数的乘积时,对于n=左*右,p1跟p2可以任意分配在左和右,它们的方案是类乘的,所以f(p1*p2)=f(p1)*f(p2)

      这里可以看出f(n)是个积性函数,那说明我们可以把它通过线性筛筛出来。

      那我们就要考虑n=pk的时候,当k>2时,对于n=左*右,不管哪个方案,左或者右那边必定有一边是存在因子包含p2的,所以此时f(pk)=0,k>2

      k=1时便是n=p,而k==2时呢,p只能分别在左右两边各一个,f(p2)=1

      最后推广n=p1k1*p2k2的时候,k1,k2肯定都不能>2,然后就是(0,0),(0,1),(0,2),(1,0),(1,1,)(1,2),(2,0)(2,1)(2,2)这九种,推导一下就是f(p1k1*p2k2)=f(p1k1)*f(p2k2)

      具体编程实现上的话,因为欧拉筛对于每个数来说,是通过它的最小质因子来筛掉它,那么我们可以记录每个数的最小质因子的指数exp,详情见注释

     1 #include<cstdio>
     2 typedef long long ll;
     3 const int N=20000007;
     4 bool nop[N]={false};
     5 int pn,pri[N/10],exp[N],f[N];
     6 void init()
     7 {
     8     f[1]=1;
     9     for(int i=2;i<N;i++)
    10     {
    11         if(!nop[i])
    12         {
    13             f[i]=2;
    14             exp[i]=1;
    15             pri[pn++]=i;
    16         }
    17         for(int j=0;j<pn&&1ll*i*pri[j]<N;j++)
    18         {
    19             int pp=i*pri[j];
    20             nop[pp]=true;
    21             //欧拉筛中,pri[j]是pp的最小质因子 
    22             if(i%pri[j]==0)
    23             {
    24                 //i的质因子有pri[j],pp的最小质因子的指数就是exp[i]+1 
    25                 exp[pp]=exp[i]+1;
    26                 if(exp[pp]>2)
    27                     f[pp]=0;
    28                 else
    29                     f[pp]=f[i/pri[j]];
    30                 //在i的方案上,再加入一个pri[j],不能跟i中原来有的
    31                 //pri[j]在同一边,而在对立边时,i中原来有的pri[j]
    32                 //在左,在右都一样,对方案没有了影响,所以 
    33                 //f[i*pri[j]]=f[i/pri[j]];
    34                 break;
    35             }
    36             //i的质因子没有pri[j],那么pp中只有一个pri[j] 
    37             exp[pp]=1;
    38             f[pp]=f[i]*f[pri[j]];
    39         }
    40     }
    41     for(int i=1;i<N;i++)
    42         f[i]+=f[i-1];
    43 }
    44 int main()
    45 {
    46     init();
    47     int t,n;
    48     scanf("%d",&t);
    49     while(t--)
    50     {
    51         scanf("%d",&n);
    52         printf("%d
    ",f[n]);
    53     }
    54     return 0;
    55 } 
    线性啊欧拉啊

      对于f[pp]=f[i/pri[j]]处,我说得不是很清楚,也不知道怎么表达那个意思,可以自行模拟体会一下。

  • 相关阅读:
    本学期3个sprint的团队贡献分
    sprint3个人总结
    12.17第九天
    阶段二总结
    sprint 1 总结
    冲刺一
    课程设计团队信息
    学习进度表
    Sprint3总结
    Res_Orders_02
  • 原文地址:https://www.cnblogs.com/LMCC1108/p/11100571.html
Copyright © 2020-2023  润新知