bzoj3629 [JLOI2014]聪明的燕姿——DFS+约数和定理

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3629

扫除了一个知识盲点:约数和定理

约数和定理:

对于一个大于1正整数n可以分解质因数:n=p1^a1*p2^a2*p3^a3*…*pk^ak,则由约数个数定理可知n的正约数有(a₁+1)(a₂+1)(a₃+1)…(ak+1)个,那么n的(a₁+1)(a₂+1)(a₃+1)…(ak+1)个正约数的和为f(n)=(p1^0+p1^1+p1^2+…p1^a1)(p2^0+p2^1+p2^2+…p2^a2)…(pk^0+pk^1+pk^2+…pk^ak)

所以就可以搜索了,可是我搜索好蒻啊不会...

参考这篇博客:https://blog.csdn.net/eolv99/article/details/39644419

于是写了一下,但感觉还是没有领悟设计 dfs 的方法...

另外,输出那里注释掉的写法为什么一直WA明明我觉得没什么问题啊...

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int const maxn=1e5;
int s,pri[maxn+5],ans[maxn+5],cnt,num;
bool vis[maxn+5];
void init()
{
    vis[1]=1;
    for(int i=2;i<=maxn;i++)
    {
        if(!vis[i])pri[++cnt]=i;
        for(int j=1;j<=cnt&&i*pri[j]<=maxn;j++)
        {
            vis[i*pri[j]]=1;
            if(i%pri[j]==0)break;
        }
    }
}
bool ispri(int x)
{
    if(x<=maxn)return !vis[x];
//    for(int i=2;i*i<=x;i++)
//        if(x%i==0)return 0;
    for(int i=1;pri[i]*pri[i]<=x;i++)
        if(x%pri[i]==0)return 0;
    return 1;
}
void dfs(int last,int nw,int tot)
{
    if(tot==1){ans[++num]=nw; return;}
    if(tot-1>pri[last]&&ispri(tot-1))//tot-1>pri[last],否则可能之后被枚举到 
    {
        ans[++num]=nw*(tot-1); //此处不return  
    }
    for(int i=last+1;pri[i]*pri[i]<=tot;i++)
        for(int t=pri[i],ts=pri[i]+1;ts<=tot;t*=pri[i],ts+=t)//+1是pri[i]^0 
            if(tot%ts==0)//!
                dfs(i,nw*t,tot/ts);
}
int main()
{
    init();
    while(~scanf("%d",&s))
    {
        num=0;
        dfs(0,1,s);
        sort(ans+1,ans+num+1);
        printf("%d\n",num);
//        for(int i=1;i<num;i++)printf("%d ",ans[i]);
//        printf("%d\n",ans[num]);
        for(int i=1;i<=num;i++)
        {
            printf("%d",ans[i]);
            if(i==num)printf("\n"); else printf(" ");
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Zinn/p/9265221.html