ACM-ICPC 2018 南京赛区网络预赛 J.SUM(线筛)

链接
题意:给出一个f函数,定义为 把i拆分成两个因子的方案数(且每一个因子都不能被平方数整除),求 ni=1f(i) ∑ i = 1 n f ( i )

分析:首先我们考虑f(i)如何求
对于任意一个i,我们可以拆分成素因子的乘积形式
此时就可以根据素因子的幂分为3种情况讨论

1.素因子的幂>=3时,由于只能拆分成两个因子无论怎么组合,f(i)一定为0
2.素因子的幂=2,此时只能将这个素因子两边各放一个
3.素因子的幂=1,此时既将这个素因子 可以放左边的因子,也可以放右边因子,对f贡献*2

f知道怎么求了,观察数据规模n<=2e7,那么肯定是要线性解决,由于还要求素因子,于是想到线性筛法,那么我们能否改造一下线筛,让它可以在筛的时候把f也计算出来

观察线筛,发现,每次他都用 i*prime[j]去筛素数
假设 此时prime[j]在i*prime[j]的因子中只出现了一次,那么f[i*prime[j]]=f[i]*2
如果 prime[i]在他的因子中出现了多次呢?如果出现多次,那么此时i%prime[j]一定是等于0的,这时候我们就把 f[i*prime[j]]/=4,因为一个prime[j]会让f变为原来的2倍,而i里又包含了一个prime[j],所以要除4

这时候只算对了2和3的情况,对于1情况,可以暴力搞一下,3次方的话复杂度也不大

还有代码里的 f初值赋为-1仅仅是因为meset不能赋值为1,没有别的意图。。。

#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long ll;
const int M=2e7+200;

int prime[M/10],tot,f[M];
bool isprime[M];
void init()
{
    memset(f,-1,sizeof(f));
    f[1]=1;
    isprime[1]=1;
    for(int i=2; i<M; i++)
    {
        if(!isprime[i])
        {
            prime[tot++]=i;
            f[i]=-2;
        }
        for(int j=0; j<tot&&i*prime[j]<M; j++)
        {
            isprime[i*prime[j]]=1;
            f[i*prime[j]]=f[i]*2;
            if(i%prime[j]==0)f[i*prime[j]]/=4;
            if(i%prime[j]==0)
                break;
        }
    }
    for(ll i=2;i*i*i<M;i++)
    {
        ll x=i*i*i;
        for(int j=2;j*x<M;j++)
            f[j*x]=0;
    }
    for(int i=2;i<M;i++)
    f[i]=abs(f[i])+abs(f[i-1]);

}
int main()
{
    init();
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
       printf("%d\n",f[n]);
    }

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值