湘大 XTU OJ 1345 素数字符串 题解:欧拉筛法 前缀和 ‘\0‘ sprintf

链接

素数字符串

题目

题目描述

我们将素数从小到大依次书写,可以得到一个字符串"23571113⋯",已知一个数码d(0≤d≤9),求字符串在区间[L,R]之间的多少个d?

输入

第一行是一个整数T(1≤T≤10000),表示样例的个数。 每个样例是一行, 为3个整数,区间L,R,(1≤L≤R≤1000000)和数码d。 区间从1开始计数。

输出

每行输出一个样例的结果。

样例输入

2
1 8 1
1 8 4

样例输出

3
0

代码

#include
#include

using namespace std;

bool isprime[2100000];//这个为什么要2100000,开成1100000,为啥不行,或者说这个要怎么
//设置,我开大一点就超出空间限制了
int prime[110000];
int res[11][1100000];

void oula()
{
	int cnt=0;
	memset(isprime,true,sizeof(isprime));
	
	isprime[0]=isprime[1]=false;
	
	for(int i=2;i<2100000;i++)
	{
		if(isprime[i])	prime[++cnt]=i;//从1开始计数
		
		for(int j=1;j<=cnt&&i*prime[j]<2100000;j++)
		{
			isprime[i*prime[j]]=false;
			if(i%prime[j]==0)	break;
		}
	}
}

void prime_table()
{
	char s[11];
	int count=0;
	for(int i=1;prime[i]!=0;i++)
	{
		memset(s,'\0',sizeof(s));
		sprintf(s,"%d",prime[i]);
		
		for(int j=0;s[j]!='\0';j++)
			for(int k=0;k<=9;k++)
				if(s[j]==(char)(k+48))	res[k][count+j+1]=1;
		
		count+=strlen(s);
	}
}

void front_sum()
{
	for(int i=0;i<=9;i++)
		for(int j=1;j<=1100000;j++)
			res[i][j]+=res[i][j-1];
}

int main()
{
	oula();
	prime_table();
	front_sum();
	
	int t;
	scanf("%d",&t);
	
	while(t--)
	{
		int l,r,d;
		scanf("%d%d%d",&l,&r,&d);
		
		printf("%d\n",res[d][r]-res[d][l-1]);
	}
	
	return 0;
}

总结

1. '\0'是什么意思:

'\0'表示空字符,是判断字符串结束的标志,它的ASCII数值是0 

#include

using namespace std;

int main()
{
	printf("%d",'\0');
	
	return 0;
}

参考链接:c语言中‘\0‘ ,‘0‘, “0“ ,0的区别

2.欧拉筛法

#include
#include

using namespace std;

const int N=1e8;

bool isprime[N];
int prime[N];

int n,cnt;

void oula()
{
	memset(isprime,true,sizeof(isprime));
	
	isprime[0]=isprime[1]=false;
	
	//cnt=0;
	
	for(int i=2;i<=n;i++)
	{
		if(isprime[i])	prime[++cnt]=i;
		
		for(int j=1;j<=cnt&&i*prime[j]<=n;j++)
		{
			isprime[i*prime[j]]=false;
			if(i%prime[j]==0)	break;
		}
	}
}

int main()
{
	scanf("%d",&n);
	
	oula();
	
	for(int i=1;i<=cnt;i++)
		printf("%d ",prime[i]);
	
	return 0;
}

参考链接:【算法/数论】欧拉筛法详解:过程详述、正确性证明、复杂度证明

3.sprintf函数的使用

相当于把双引号里面的内容输出到数组里面保存,并且是把一个一个字符存在数组里面

#include
#include

using namespace std;

int main()
{
	int a=12345;
	char s[10];
	
	sprintf(s,"%d",a);
	
	printf("%s",s);
	
	printf("\n");
	
	printf("%c",s[0]);
	
	return 0;
}

比如说这个代码是把整型变量a存在字符串数组s里面 

参考链接:2.C语言基础-sprintf函数用法 

4. i++和++i是有区别的,i++是使用自增之前的数值,++i是使用自增之后的数值,前缀和一般从1开始计数比较方便,所以

res[k][count+j+1]=1;

加上一,从1开始计数

5.这个分为三个函数,第一个函数是欧拉筛法,第二个函数是素数打表,第三个函数是求前缀和,前缀和的公式:前缀和 

6.欧拉筛法前面说了,是一个时间复杂度是线性的模板

7.素数打表,遍历每一个素数,把每一个素数转换成数组元素,意思是12345转换成‘1’‘2’‘3’‘4’‘5’ 存在数组里面,然后遍历这个数组,再遍历0-9每一个数字,如果相等就把计数的二维数组的对应位置标记为1,在遍历数组,遍历0-9循环外面,计算一个count,等于这个数组实际使用到的长度,这样可以使得标记的位置不会重叠,二维数组的指针会不断的往后移动(可以这么理解)

8.前缀和,二维数组行列,不看行就是普通的前缀和,对每一列使用前缀和的预处理

9.最后调用前缀和公式就可以解决这个题目

湘大 XTU OJ 1345 素数字符串 题解:欧拉筛法 前缀和 ‘\0‘ sprintf_第1张图片

 

你可能感兴趣的:(算法竞赛,湘大,XTU,OJ,c++,算法,开发语言)