CodeForces 542D. Superhero's Job 暴力数论

看出这一点,接下来只需要对A进行上述分解,有多少种分解,就有多少个答案。

由于每个p都是不一样的,所以找出的因子一定没有相等的,于是每种分解都可以按照从小到大排列。

于是每找出一个因子,都记下这个因子,并在接下来的寻找中,

忽略这个因子对应的质数,并且忽略小于这个因子的分解,这样可以避免重复,具体见代码。

简单来说,就是暴力递归出所有分解。

CF上的题解是用的DP,不过我暴力分解也过了。又一道被我暴力水过的,标答是DP的数论题

只能说数论题一般的分解情况比较少,暴力+优化就过了。这题,答案将近100万的都可以在1s内跑完暴力程序。

给一个大的例子:A=963761198400 时,答案为 100049


代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#define out(i) <<#i<<"="<<(i)<<"  "
#define OUT1(a1) cout out(a1) <<endl
#define OUT2(a1,a2) cout out(a1) out(a2) <<endl
#define OUT3(a1,a2,a3) cout out(a1) out(a2) out(a3)<<endl
#define maxn 1000007 
#define LL long long
using namespace std;
int maxprime[maxn];//maxprime[i]:i的最大质因数 
int prime[100000],N;//prime[i]:第i个质数 
int keyprime[maxn];//keyprime[i]:若i=1+p^k 则keyprime[i]=k 否则 keyprime[i]=0 
int nextkeyprime[maxn];//记录下一个不为零的keyprime,加快计算过程 
void Init(){//初始化 
	memset(maxprime,0,sizeof(maxprime));
	memset(keyprime,0,sizeof(keyprime));
	keyprime[1]=1;
	N=0;
	for(int i=2;i<maxn;++i){
		if(maxprime[i]) continue;
		prime[N++]=i;
		for(int j=i;j<maxn;j+=i) maxprime[j]=i;
		for(LL j=1;j<=(maxn-2)/i;){
			j*=i;
			keyprime[j+1]=i;
		}
	}
	nextkeyprime[maxn-1]=maxn-1;
	for(int i=maxn-1;i>0;--i){
		if(keyprime[i]) nextkeyprime[i-1]=i;
		else nextkeyprime[i-1]=nextkeyprime[i];
	}
}
int Sqrt(LL x){//求floor(sqrt(x)) 
	LL L=1,R=1000007;//[L,R)
	while(L+1 < R){
		LL M=(L+R)>>1;
		if(M*M <= x) L=M;
		else R=M;
	}
	return (int)L;
}
LL KeyPrime(LL x){//求x是否为某质数p的某个正次方 ,是的话返回这个质数,否则返回0 
	if(x+1 < maxn) return keyprime[x+1];//对于小的x直接利用keyprime数组 
	int KeyP=0;int sqx=Sqrt(x);
	for(int i=0;i<N;++i){
		if(x%prime[i]==0) {
			KeyP=prime[i];
			break;
		}
		if(prime[i]>sqx) break;//及时退出 
	}
	if(KeyP){
		while(x%KeyP==0) x/=KeyP;
		if(x==1) return KeyP;
		else return 0;
	}
	else return x;//此时x就是个大质数 
}

LL x;
int p[20],n;//记录已经进行的分解中用到的质数 
bool exist(int k){//判断k是否存在
	for(int i=0;i<n;++i) if(p[i]==k) return true;
	return false;
}
int ANS;
void F(LL x,LL v){//x:当前待分解的数,v:当前因数的最大值 
	int top=Sqrt(x);
	LL KP=KeyPrime(x-1);//判断x是否可以被分解成1+p^k 
	if(KP&&!exist(KP)) ++ANS;//如果这个因子没出现过,答案+1 
	p[n++]=KP;
	//除掉最小的因子,继续递归 
	for(int i=nextkeyprime[v];i<=top;i=nextkeyprime[i]){
		//OUT2(i,top);
		if(x%i==0&&!exist(keyprime[i])){
			p[n++]=keyprime[i];
			F(x/i,i);
			--n;
		}
	}
	--n;
}
int main(void)
{
	Init();
	while(cin>>x){
		int sqx=Sqrt(x);
		n=0;ANS=0;
		F(x,2);
		cout<<ANS <<endl;
	}
return 0;
}





 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值