20240405比賽總結

wangsiqi2010916發表於2024-04-05

寄的很慘

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;
}