真·题·再·现
【题目描述】
恭喜王哲涵同学和姜昊志同学分别获得可达鸭十月月赛——基础赛第二场的第三名和第五名的好成绩!
老师课堂上刚讲了数位分离和判断素数,就顺利成章的想找王哲涵同学和姜昊志同学搭档,王哲涵同学负责把n
及以内的数据全都分离各个位,姜昊志同学负责统计这些位是素数的个数。
数位分离就是,把一个整数的各个位能单独分出来,比如一个数字是3241
,单独分出数字3
,数字2
,数字4
,数字1
。
判断素数的条件就是,一个数的因子只有1
和它本身,比如一个数字7
,它的因子只有1
和7
,也就是不能被其他数字整除。
例如:n=12
,n
及以内的数据为:1,2,3,4,5,6,7,8,9,10,11,12
,这些数据的各位分别是:1,2,3,4,5,6,7,8,9,1,0,1,1,1,2
,这些数一共是5
个素数。
【输入描述】
共有T
组数据。
第一行,一个整数T
,表示共有T
组测试数据。
接下来T
行,每行一个整数n
,表示数位分离n
及以内的数。
【输出描述】
共T
行,每行一个整数,表示分离n
及以内的数所有位中出现的素数个数。
【输入样例】
2
12
30
【输出样例】
5
23
【数据范围】
对于100%
的数据,1<=T<=100
,1<=n<=10000
。
解·题·思·路
【题目分析】
本题数据量较大,如果遍历1~n
一个一个数位分离再找素数很浪费时间(大悲)。要解决这个问题,不能强夺,而事要智取(意味深)。
【解题过程】
他来了他来了,老三样他走来了!
using namespace std;
int main(){
}
题目要求将各位数字拆分后求质数,所以只需要求0~9
的质数即可。
using namespace std;
int p[10]={0,0,1,1,0,1,0,1,0,0};//0~9的质数有2、3、5、7
int main(){
}
主函数读入T
,此时需要cstdio
头文件。
#include<cstdio>
using namespace std;
int p[10]={0,0,1,1,0,1,0,1,0,0};//0~9的质数有2、3、5、7
int main(){
int t;
scanf("%d",&t);//读入T
}
接下来循环T
次读入n
,为了省一个循环变量,用while
代替for
。
#include<cstdio>
using namespace std;
int p[10]={0,0,1,1,0,1,0,1,0,0};//0~9的质数有2、3、5、7
int main(){
int t,n;
scanf("%d",&t);//读入T
while(t--){//为了省一个循环变量,用while代替for
scanf("%d",&n);
}
}
然后考虑读入n
之后的输出,一定要预处理,不然多看一眼就会爆炸!!!(指爆零)
声明一个数组dp
,用dp[i]
表示读入的n=i
时输出的数。
不难发现,当n=1
时,输出的数为0
,那么dp[1]=0
;n=2
时,考虑数位分离判断质数,得出“状态转移方程”:dp[i]=dp[i-1]+solve(i)
,其中solve(i)
表示数位分离的质数个数。
#include<cstdio>
using namespace std;
int dp[10086]={0,0};//将dp[1]初始化为0
int p[10]={0,0,1,1,0,1,0,1,0,0};//0~9的质数有2、3、5、7
int SOLVE(int n){//整道题最费脑子的部分,这里最好写一个函数循环调用
int cnt=0;//声明一个cnt变量,记录数位分离后质数的个数
while(n){
cnt+=p[n%10];//如果n的个位是质数,将cnt增加1,否则不变
n/=10;//将n的个位去掉,原数的十位即新数的个位
}
return cnt;//必须要有返回值,不然会被撅!!!(恼)
}
int main(){
for(int i=2;i<10086;i++)dp[i]=dp[i-1]+SOLVE(i);//将SOLVE函数的值递推写入dp数组,注意这行代码必须放到主函数的开头,不然输出可能全0
int t,n;
scanf("%d",&t);//读入T
while(t--){//为了省一个循环变量,用while代替for
scanf("%d",&n);
printf("%d",dp[n]);//输出dp[n]的值
if(t)puts("");//puts()输出时会自动添加换行,注意括号里要有一对双引号,不然会被撅!!!(恼)
}
return 0;//这一句可有可无,但是某些比赛可能会有要求
}
【测试结果】
全部样例均正确,以以有,阔以有!(赞赏)
谢谢观看!!!