BZOJ 3629 JLOI2014 聪明的燕姿 约数和+DFS

题目大意:令f(x)=Σi (i|x) 给定n,求所有的x,使f(x)=n

这题就是今年省选第二题,我没看到多组数据爆零了,不然妥妥30分。。。

首先约数和公式

令n=p1^a1*p2^a2*...*pk^ak

则f(n)=(1+p1+p1^2+...+p1^a1)*(1+p2+p2^2+...+p2^a2)*...*(1+pk+pk^2+...+pk^ak)

于是我们枚举质数p,采取DFS的方式求出所有值

记住DFS时无论什么操作都要O(√n),O(n)必死,O(n/logn)必死,包括枚举质数的时候要用O(√left)的,O(√n)都是死 其中left是n/当前数字的约数和

BZOJ是算总时间的 所以很多人都水过去了 第十个点全都是反质数 O(√n)必死 学校的大神还出了个第十一个点 能把O(√n)卡出14秒 O(√left)秒过

此外枚举质数时别出现重复 这题有的OJ在答案为零的时候要输出一个空行 BZOJ不用打

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 100100
using namespace std;
typedef long long ll;
ll n,p[M],ans[M],tot;
bool not_prime[M];
void Get_Prime()
{
    int i,j;
    for(i=2;i<=100000;i++)
    {
        if(!not_prime[i])
            p[++p[0]]=i;
        for(j=1;p[j]*i<=100000&&j<=p[0];j++)
        {
            not_prime[p[j]*i]=1;
            if(i%p[j]==0)
                break;
        }
    }
}
bool Judge_Prime(ll x)
{
    ll i;
    if(x==1)
        return 0;
    for(i=1;p[i]*p[i]<=x;i++)
        if(x%p[i]==0)
            return 0;
    return 1;
}
void DFS(ll now,int pos,ll left)
{
    int i;
    if(left==1)
    {
        ans[++ans[0]]=now;
        return ;
    }
    if( left-1>=p[pos] && Judge_Prime(left-1) )
        ans[++ans[0]]=(left-1)*now;
    for(i=pos; p[i]*p[i]<=left ;i++)
    {
        ll power_sum=p[i]+1,power=p[i];
        for(;power_sum<=left;power*=p[i],power_sum+=power)
            if(left%power_sum==0)
                DFS(now*power,i+1,left/power_sum);
    }
}
int main()
{
    int i;
    
    //freopen("swallow.in","r",stdin);
    //freopen("swallow.out","w",stdout);
	
    Get_Prime();
    while(~scanf("%lld",&n) )
    {
        ans[0]=0;tot=0;
        DFS(1,1,n);
        sort(ans+1,ans+ans[0]+1);
  		cout<<ans[0]<<endl;
        for(i=1;i<=ans[0];i++)
   	    	printf("%lld%c",ans[i],i==ans[0]?'\n':' ');
        //if(!ans[0])
        //	cout<<endl;
    }
}
对比一下最后一个点

void DFS(ll now,int pos,ll left)
{
    int i;
    if(left==1)
    {
        ans[++ans[0]]=now;
        return ;
    }
    if( (left-1)*(left-1)>=n && Judge_Prime(left-1) )
        ans[++ans[0]]=(left-1)*now;
    for(i=pos;p[i]<=left&&p[i]*p[i]<=n;i++)
    {
        ll power_sum=p[i]+1,power=p[i];
        for(;power_sum<=left;power*=p[i],power_sum+=power)
            if(left%power_sum==0)
                DFS(now*power,i+1,left/power_sum);
    }
}
O( min(√n,left) ) 14s出解

void DFS(ll now,int pos,ll left)
{
    int i;
    if(left==1)
    {
        ans[++ans[0]]=now;
        return ;
    }
    if( (left-1)*(left-1)>=n && Judge_Prime(left-1) )
        ans[++ans[0]]=(left-1)*now;
    for(i=pos;p[i]*p[i]<=n;i++)
    {
        ll power_sum=p[i]+1,power=p[i];
        for(;power_sum<=left;power*=p[i],power_sum+=power)
            if(left%power_sum==0)
                DFS(now*power,i+1,left/power_sum);
    }
}

O(√n) 被卡了整整100s都没出解

你可能感兴趣的:(数论,DFS,bzoj,BZOJ3629,约数和)