2020 ccpc-good number

2020 ccpc-good number

题意

如果一个数字是Good Number,当且仅当x开K次方后,能整除 x 。(注意是整除x,不是整除以x) 即x能整除以(x开K次方后的数)

现在给出 n,k ,求 1 到 n 之中Good Number 的个数。

输入

第一个一个整数 T 表示测试组数。

之后每一行两个正整数 n,k。

1≤T≤10

1≤n,k≤10e9

输出

"Case #x: y"格式输出,一行一个答案。

样例

输入:

2
233 1
233 2

输出:

Case #1: 233
Case #2: 43

思路:特判一部分数据,暴力一部分数据,就不会超时啦!

(1) 当k==1时,1~n内所有数开一次方都是其本身,所以必然会被本身所除!即输出结果为n

(2) 当k>=30时 因为2^30=1073741824 大于题目所给的范围,所以在题目所给范围的任意一个数,开30次方后,向下取整,结果都为1,这时(题意中)任何数除以1都等于本身,都可满足条件,所以输出结果为n

(3) 2~30以内 以k=2为例:

​ 【1,3】 开K次方后,向下取整为1,所以这区间里面三个数都可以

​ 【4,8】开K次方后,向下取整为2,可以整除的数有4 6 8 三个

​ 【9,15】开K次方后,向下取整为3,可以整除的数有 9 12 15 三个

​ 【16,24】开K次方后,向下取整为4,有16 20 24

发现可行的个数=区间的两端的数值相减/此区间对应的向下取整的数;

即【1,3】–>(3-1)/1+1

​ 【4,8】–>(8-4)/2+1。。。

其实k=3 4 5…都是一样的,不信你在纸上推算一下!

好了,是不是感觉说了个寂寞,还是没看懂?那。。。
看代码吧。。。

#include<bits/stdc++.h>
using namespace std;
long long a[4000000],b[4000000];//a记录次方数,b记录底数 

//先来个快速幂模板 
long long fastpow(long long a,long long b)//辅助找到a b里面的值
{
    
    
	long long re=1;
	while(b)
	{
    
    
		if(b&1) re*=a;
		a=a*a;
		b>>=1;
	} 
	return re;
} 

int main()
{
    
    
	int t;
	scanf("%d",&t); 
	 
	for(int o=1;o<=t;o++)
	{
    
    
		long long n,k;
		scanf("%lld%lld",&n,&k);
		if(k==1||k>=31) //保险一点搞31吧 (怂怂的小声BB) 
		{
    
    
		  printf("Case #%d: %lld\n",o,n);
		  continue;	
		}
 	
		long long j=1,len=0;
		for(int i=1;;i++)
		{
    
    
			long long x=fastpow(j,k);
			if(x>n) break;//如果范围超出的话,跳出循环
			
			a[i]=x;//记录次方数 
			b[i]=j;//记录底数 
			j++; 
		    len++;
		}
		long long res=0;//记录结果
		
		for(int i=2;i<=len;i++)
		{
    
    
			res+=(a[i]-1-a[i-1])/b[i-1]+1;
			//printf("%lld %lld %d\n",a[i]-1-a[i-1],b[i-1],res);
		}
			 
		
		//如果n是一个次方数,直接加上1
		if(b[len]==n) res+=1;
		
		else res+=(n-a[len])/b[len]+1;
		printf("Case #%d: %lld\n",o,res); 
	}
	return 0;
} 

运行正确`(∩_∩)′
在这里插入图片描述

然后。。。欢迎大家友好评论哈,要是哪里不对的,我再修改修改<(ToT)>,哪里语言表达不清的,我再学学语文?

猜你喜欢

转载自blog.csdn.net/m0_46288176/article/details/109213569