寄的很慘
T1 [JLOI2014] 聰明的燕姿
https://gxyzoj.com/d/hzoj/p/3672
敲個警鐘,千萬不要用一些奇怪的方法寫自己會的題,不然大機率會一分不剩
由小學奧數知識,約數和的求法為\(\prod (1+p_i^2+p_i^3+\dots+p_i^{a_i})\)
所以,可以先線性預處理出約數和,再直接統計,時間複雜度\(O(nk)\),顯然會T
考慮最佳化,顯然,約數和也是一個乘積所以可以列舉其因子,注意,同一個p只可以使用一次
所以可以dfs,記錄當前的答案和剩餘的數,但是,2e9以內的質數不會少於5e7個,所以,還要最佳化
因為一個數n中不會出現兩個超過\(\sqrt n\)的因數,所以,考慮只列舉\(\sqrt{10^9}\)以內的因數,其餘暴力判斷即可
程式碼:
#include<cstdio>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int N=2e9;
int s,idx,ans,t[100005];
bool get_prime(int x)
{
if(x==1||x==0) return 0;
for(int i=2;i<=x/i;i++)
{
if(x%i==0) return 0;
}
return 1;
}
int cnt,p[50005];
bool vis[50005];
void dfs(int x,int num,int id)
{
//printf("%d %d %d\n",x,num,id);
if(x==1)
{
t[++ans]=num;
return;
}
for(int i=id;i<=cnt&&p[i]*p[i]<=x;i++)
{
ll tmp=1,sum=1;
for(int j=1;;j++)
{
tmp*=p[i];
sum+=tmp;
if(sum<=x)
{
if(x%sum==0)
{
dfs(x/sum,num*tmp,i+1);
}
}
else break;
}
}
if(get_prime(x-1)&&x-1&&x-1>=p[id]) t[++ans]=(x-1)*num;
}
int main()
{
for(int i=2;i<=50000;i++)
{
if(!vis[i]) p[++cnt]=i;
for(int j=1;i*p[j]<=50000;j++)
{
vis[i*p[j]]=1;
if(i%p[j]==0) break;
}
}
while(cin>>s)
{
ans=0;
dfs(s,1,1);
sort(t+1,t+ans+1);
int tmp=ans;
for(int i=1;i<=ans;i++)
{
if(t[i]==t[i-1]) tmp--;
}
printf("%d\n",tmp);
for(int i=1;i<=ans;i++)
{
if(t[i]!=t[i-1]) printf("%d ",t[i]);
}
if(ans)
printf("\n");
}
return 0;
}