PAT 乙级讲题记录

1003 我要通过! (20分)

1003 我要通过

题目描述

答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。

得到“答案正确”的条件是:

1.字符串中必须仅有 P、 A、 T这三种字符,不可以包含其它字符;
2.任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x 或者是空字符串,或者是仅由字母 A 组成的字符串;
3.如果 aPbTc 是正确的,那么 aPbATca 也是正确的,其中 a、 b、 c 均或者是空字符串,或者是仅由字母 A 组成的字符串。

现在就请你为 PAT 写一个自动裁判程序,判定哪些字符串是可以获得“答案正确”的。

输入格式:

每个测试输入包含 1 个测试用例。第 1 行给出一个正整数 n ( < < < 10),是需要检测的字符串个数。接下来每个字符串占一行,字符串长度不超过 100,且不包含空格。

输出格式:

每个字符串的检测结果占一行,如果该字符串可以获得“答案正确”,则输出 YES,否则输出 NO。

样例
输入样例:

8
PAT																
PAAT														
AAPATAA													
AAPAATAAAA												
xPATx															
PT															
Whatever														
APAAATAA	

输出样例:

YES
YES
YES
YES
NO
NO
NO
NO

Solution

条件1:仅包含P、A、T
条件2:P和T仅有一个,A ≥ \ge 1
条件3:若 aPbTc 合法,那么 aPbATca 也合法我们可以得到,如果P和T中间的A的数量增加了1个,那么T之后的A的数量增加了a个。
令P前的A数量为x,P和T之间的A数量为y,T之后的A数量为z,可得:

x * y = z

代码

#include <bits/stdc++.h>
using namespace std;
const int SZ = 100 + 5;
char s[SZ];

int main()
{
	int T;
	scanf("%d",&T);
	while(T --)
	{
		scanf("%s",s);
		int posp = 0,post = 0,nump = 0,numa = 0,numt = 0; // P的位置、T的位置、p的数量、a的数量、t的数量。 
		int prea = 0,ina = 0,posta = 0;// x 、 y 、 z 
		for(int i = 0;i < strlen(s);i ++)
		{
			if(s[i] == 'A') numa ++;
			if(s[i] == 'P')
			{
				posp = i;
				nump ++;
			}
			if(s[i] == 'T')
			{
				post = i;
				numt ++;
			}
		}
		if(nump == 1 && numt == 1 && numa >= 1 && nump + numa + numt == strlen(s)) //条件1、2 
		{
			prea = posp;
			ina = post - posp - 1;
			posta = numa - prea - ina;
			if(prea * ina == posta) printf("YES\n"); // 条件3 
			else printf("NO\n");
		} 
		else printf("NO\n");
	}
	return 0;
} 

1013 数素数 (20分)

1013 数素数

题目描述

P ​ i P_​i Pi表示第 i 个素数。现任给两个正整数 M ≤ \le N ≤ \le 1 0 4 10^4 104,请输出 P M P_M PM P N P_N PN的所有素数。

输入格式:

输入在一行中给出 M 和 N,其间以空格分隔。

输出格式:

输出从 P M P_M PM P N P_N PN 的所有素数,每 10 个数字占 1 行,其间以空格分隔,但行末不得有多余空格。

输入样例:

5 27

输出样例:

11 13 17 19 23 29 31 37 41 43
47 53 59 61 67 71 73 79 83 89
97 101 103

Solution

两种素数筛

埃氏筛
O( n log ⁡ 2 log ⁡ 2 n n\log_2{\log_2n} nlog2log2n)

在这里插入图片描述

for(int i = 2;i <= n;i ++)
{
	if(prime[i] == 0)
	{
		p[ ++ tot] = i;
		for(int j = 2;j * i <= n;j ++ )
			prime[j * i] = 1;	
	}
} 

欧拉筛
O( n n n)

埃氏筛的缺陷:同一个合数有可能被多个素数筛。
欧拉筛克服了这一缺陷,每个合数只被最小质因子来筛,复杂度也就是线性的。

int p[SZ],prime[SZ];

inline void e_prime(int N);
{ 
	int tot = 0;
	for(int i = 2;i <= N;i ++ )
	{
		if(prime[i] == 0) p[ ++ tot] = i;
		for(int j = 1;j <= tot && i * p[j] <= N;j ++)
		{
			prime[i * p[j]] = 1;
			if(i % p[j] == 0) break;
		}
	}
} 

代码

#include <bits/stdc++.h>
using namespace std;
const int SZ = 110000;
map<int,int>prime;
vector<int> p; 

/*inline void sieve() //埃氏筛
{
	for(int i = 2;i <= SZ;i ++)
	{
		if(prime[i] == 0)
		{
			p.push_back(i);
			for(int j = 2;j * i <= SZ;j ++) prime[j * i] = 1;
		}
	}
}*/

inline void e_prime() //欧拉筛
{	
	for(int i = 2;i <= SZ;i ++)
	{
		if(prime[i] == 0) p.push_back(i);
		for(int j = 0;j < p.size() && i * p[j] < SZ;j ++)
		{
			prime[i * p[j]] = 1;
			if(i % p[j] == 0) break;
		}
	}
}

int main()
{
	//sieve();
	e_prime();
	int n,m;
	scanf("%d%d",&n,&m);
	int cnt = 0;
	for(int i = n - 1;i <= m - 1;i ++)
	{
		cnt ++;
		if(i == m - 1) printf("%d",p[i]);
		else printf("%d%c",p[i],(cnt % 10 == 0) ? '\n' : ' ');
	}
	return 0;
}

1027 打印沙漏 (20分)

1027 打印沙漏

题目描述

本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”,要求按下列格式打印:

*****
 ***
  *
 ***
*****

所谓“沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数先从大到小顺序递减到1,再从小到大顺序递增;首尾符号数相等。

给定任意N个符号,不一定能正好组成一个沙漏。要求打印出的沙漏能用掉尽可能多的符号。

输入格式:

输入在一行给出1个正整数N( ≤ \le 1000)和一个符号,中间以空格分隔。

输出格式:

首先打印出由给定符号组成的最大的沙漏形状,最后在一行中输出剩下没用掉的符号数。

输入样例:

19 *

输出样例:

*****
 ***
  *
 ***
*****
2

Solution

首先,计算出除了最中间的一行,还要向上向下延伸的行数。
a n = 2 ∗ n + 1 a_n = 2 * n + 1 an=2n+1
S n = n ∗ ( 2 ∗ n + 1 + 3 ) / 2 = n ∗ ( n + 2 ) S_n = n * (2 * n + 1 + 3) / 2 = n * (n + 2) Sn=n(2n+1+3)/2=n(n+2)
所以 2 ∗ n ∗ ( n + 2 ) + 1 ≤ N 2 * n * (n + 2) + 1 \le N 2n(n+2)+1N的最大n就是延伸的行数

计算出延伸的行数后,就可以把沙漏分成上中下三部分打印出来。

代码

#include <bits/stdc++.h>
using namespace std;
const int SZ = 1000 + 10;
int n,N;
char ch;
int main()
{
	scanf("%d %c",&N,&ch);
	for(int i = 0;i < N;i ++)
		if(2 * i * (i + 2) + 1 > N) 
		{
			n = i - 1;
			break;
		}
	for(int i = n;i >= 1;i --)
	{
		for(int j = 1;j <= n - i;j ++) printf(" ");
		for(int j = 1;j <= i * 2 + 1;j ++) printf("%c",ch);
		printf("\n");
	}
	for(int j = 1;j <= n;j ++) printf(" ");
	printf("%c\n",ch);
	for(int i = 1;i <= n;i ++)
	{
		for(int j = 1;j <= n - i;j ++) printf(" ");
		for(int j = 1;j <= i * 2 + 1;j ++) printf("%c",ch);
		printf("\n");
	}
	printf("%d",N - 2 * n * (n + 2) - 1);
	return 0;
}

1035 插入与归并 (25分)

1035 插入与归并

题目描述

根据维基百科的定义:

插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。

归并排序进行如下迭代操作:首先将原始序列看成 N N N 个只包含 1 1 1 个元素的有序子序列,然后每次迭代归并两个相邻的有序子序列,直到最后只剩下 1 1 1 个有序的序列。

现给定原始序列和由某排序算法产生的中间序列,请你判断该算法究竟是哪种排序算法?

输入格式:

输入在第一行给出正整数 N N N ( ≤ 100 \le100 100);随后一行给出原始序列的 N N N 个整数;最后一行给出由某排序算法产生的中间序列。这里假设排序的目标序列是升序。数字间以空格分隔。

输出格式:

首先在第 1 行中输出Insertion Sort表示插入排序、或Merge Sort表示归并排序;然后在第 2 行中输出用该排序算法再迭代一轮的结果序列。题目保证每组测试的结果是唯一的。数字间以空格分隔,且行首尾不得有多余空格。

输入样例 1:

10
3 1 2 8 7 5 9 4 6 0
1 2 3 7 8 5 9 4 6 0

输出样例 1:

Insertion Sort
1 2 3 5 7 8 9 4 6 0

输入样例 2:

10
3 1 2 8 7 5 9 4 0 6
1 3 2 8 5 7 4 9 0 6

输出样例 2:

Merge Sort
1 2 3 8 4 5 7 9 0 6

Solution

插入排序
在这里插入图片描述
将无序的数列中第一个元素与有序数列的元素从后到前比较,找到插入位置,将该元素插入到有序数列的适当位置。
在此题中,若给定的中间序列符合前半部分有序,后半部分与初始序列相同,则为插入排序,否则为归并排序。

归并排序
在这里插入图片描述
归并排序的思想就是分治再合并。

如果是插入排序,就把无序序列的第一位和有序序列排一下序,输出即可。
如果是归并排序,就对初始序列模拟一下归并排序的过程,当达到中间序列时,在归并一步即可。

代码

#include <bits/stdc++.h>
using namespace std;
const int SZ = 100 + 5;
int n,a[SZ],b[SZ];

inline bool check()
{
	for(int i = 2;i <= n;i ++)
	{
		if(b[i] < b[i - 1]) 
		{
			for(int j = i;j <= n;j ++)
			{
				if(b[j] != a[j]) return 0;
			} 
			sort(b + 1,b + i + 1);
			return 1;
		}
	}	
}
int main()
{
	scanf("%d",&n);
	for(int i = 1;i <= n;i ++) scanf("%d",&a[i]);
	for(int i = 1;i <= n;i ++) scanf("%d",&b[i]);
	if(check())
	{
		printf("Insertion Sort\n");
		for(int i = 1;i <= n;i ++) printf("%d%c",b[i],i == n ? '\n' : ' ');
	}
	else 
	{
		printf("Merge Sort\n");
		int k = 1,flag = 1;
		while(flag)
		{
			flag = 0;
			for(int i = 1;i <= n;i ++)
				if(a[i] != b[i]) flag = 1;
			k <<= 1;
			for(int i = 1;i <= n / k;i ++) sort(a + (i - 1) * k + 1,a + i * k  + 1);
			sort(a + n / k * k + 1,a + n + 1);
		}
		for(int i = 1;i <= n;i ++) printf("%d%c",a[i],i == n ? '\n' : ' ');
	}
}

1040 有几个PAT (25分)

1040 有几个PAT

题目描述

字符串 APPAPT 中包含了两个单词 PAT,其中第一个 PAT 是第 2 位§,第 4 位(A),第 6 位(T);第二个 PAT 是第 3 位§,第 4 位(A),第 6 位(T)。

现给定字符串,问一共可以形成多少个 PAT?

输入格式:

输入只有一行,包含一个字符串,长度不超过 1 0 5 10^5 105,只包含 P、A、T 三种字母。

输出格式:

在一行中输出给定字符串中包含多少个 PAT。由于结果可能比较大,只输出对 1000000007 取余数的结果。

输入样例:

APPAPT

输出样例:

2

Solution

首先对于每一个A,我们只要计算它前面的P的数量和后面的T的数量的乘积,就是这个A对答案的贡献,所有A对答案的贡献即为答案。所以我们对每个A统计一下它前面的P的数量,然后再扫一遍序列,如果出现A,就把当前总的PA组合的数量记录,每出现一个T,形成了PAT,就把当前的PA组合的数量加入答案中去,最终扫完整个序列,即可求得答案。

注意:中间取余,而不是最后取余,防止爆int。

代码

#include <bits/stdc++.h>
using namespace std;
const int SZ = 1e5 + 20;
const int MOD = 1e9 + 7;
typedef long long ll; 
int prep[SZ];
char s[SZ];

int main()
{
	scanf("%s",s);
	int nump = 0;
	for(int i = 0;i < strlen(s);i ++)
	{
		if(s[i] == 'P') nump ++;
		if(s[i] == 'A') prep[i] = nump;
	}	
	ll ans = 0,sum = 0;
	for(int i = 0;i < strlen(s);i ++)
	{
		if(s[i] == 'A') sum = (sum + prep[i]) % MOD;
		if(s[i] == 'T') ans = (ans + sum) % MOD;
	}
	printf("%lld\n",ans);
	return 0;
}

1045 快速排序 (25分)

1045 快速排序

题目描述

著名的快速排序算法里有一个经典的划分过程:我们通常采用某种方法取一个元素作为主元,通过交换,把比主元小的元素放到它的左边,比主元大的元素放到它的右边。 给定划分后的 N N N 个互不相同的正整数的排列,请问有多少个元素可能是划分前选取的主元?

例如给定 N = 5 N = 5 N=5, 排列是 1 、 3 、 2 、 4 、 5 1、3、2、4、5 13245。则:

1 1 1 的左边没有元素,右边的元素都比它大,所以它可能是主元;
尽管 3 3 3 的左边元素都比它小,但其右边的 2 2 2 比它小,所以它不能是主元;
尽管 2 2 2 的右边元素都比它大,但其左边的 3 3 3 比它大,所以它不能是主元;
类似原因, 4 4 4 5 5 5 都可能是主元。
因此,有 3 3 3 个元素可能是主元。

输入格式:

输入在第 1 1 1 行中给出一个正整数 N( ≤ \le 1 0 5 10^5 105); 第 2 2 2 行是空格分隔的 N N N 个不同的正整数,每个数不超过 1 0 9 10^9 109​​ 。

输出格式:

在第 1 1 1 行中输出有可能是主元的元素个数;在第 2 2 2 行中按递增顺序输出这些元素,其间以 1 1 1 个空格分隔,行首尾不得有多余空格。

输入样例:

5
1 3 2 4 5

输出样例:

3
1 4 5

Solution

对于一个序列,如果当前数字是主元,比它小的数都在它前面,比它大的数都在他后面,那么排序后的序列中该数字的位置不变。
但是仅仅这样并不能判断它一定是主元,例如
32145 3 2 1 4 5 32145
12345 1 2 3 4 5 12345
2的位置没有发生改变,但是2前面有比它大的3,所以我们只要再判断一下当前数字是已出现数字中最大的一个即可,这样也就保证了他前面的都是比它小的,也就保证了 后面的都比它大。

代码

#include <bits/stdc++.h>
using namespace std;
const int SZ = 1e5 + 10;
int n,num[SZ],temp[SZ];

int main()
{
	scanf("%d",&n);
	for(int i = 1;i <= n;i ++) 
	{
		scanf("%d",&num[i]);
		temp[i] = num[i];
	}
	sort(temp + 1,temp + n + 1);
	vector<int> vec;
	int maxn = 0;
	for(int i = 1;i <= n;i ++)
	{
		maxn = max(maxn,num[i]);
		if(num[i] == temp[i] && maxn == num[i]) vec.push_back(num[i]);
	} 
	int N = vec.size();
	printf("%d\n",N);
	for(int i = 0;i < N;i ++)
		if(i != N - 1)	printf("%d ",vec[i]);
		else printf("%d",vec[i]);
	printf("\n");
	return 0; 
}

1050 螺旋矩阵 (25分)

1050 螺旋矩阵

题目描述

本题要求将给定的 N N N 个正整数按非递增的顺序,填入“螺旋矩阵”。所谓“螺旋矩阵”,是指从左上角第 1 1 1 个格子开始,按顺时针螺旋方向填充。要求矩阵的规模为 m m m n n n 列,满足条件: m × n m×n m×n 等于 N N N m ≥ n m \ge n mn;且 m − n m − n mn 取所有可能值中的最小值。

输入格式:

输入在第 1 1 1 行中给出一个正整数 N N N,第 2 2 2 行给出 N N N 个待填充的正整数。所有数字不超过 1 0 4 10^4 104,相邻数字以空格分隔。

输出格式:

输出螺旋矩阵。每行 n n n 个数字,共 m m m 行。相邻数字以 1 1 1 个空格分隔,行末不得有多余空格。

输入样例:

12
37 76 20 98 76 42 53 95 60 81 58 93

输出样例:

98 95 93
42 37 81
53 20 76
58 60 76

Solution

枚举找出 m m m n n n(或者用一点简单的数学知识优化一下)
利用while循环蛇形填数。

代码

#include<bits/stdc++.h>
using namespace std;
const int SZ = 1e5 + 5; 
int num[SZ],mp[10005][1005];
/*bool cmp(int a,int  b) 
{
   return a>b;
}*/
int main()
{
    int N,m,n;
    scanf("%d",&N);
    
   	/*int temp = 0x3f3f3f3f;
	for(int i = N;i >= 1;i --)
   	{
   		if(N % i == 0) 
   		{
   			if(i >= N / i)
   			{
   				if(i - N / i < temp)
				{
					n = N / i;
					m = i;
					temp =  i - N / i;	
				} 
   			}
   			else break;
   		}
   	}*/
   	for(int i = 1;i * i <= N;i ++)
   	{
		if(N % i == 0)
		{
			n = i;
			m = N / i; 
		}   		
   	}
    
	for(int i = 1;i <= N;i ++)
    scanf("%d",&num[i]);
    sort(num + 1,num + N + 1,greater<int>());
    
	int cnt = 0,line = 1,row = 0;
    while(cnt < N) 
    { //写法上先判断是否越界
        while(row + 1 <= n && !mp[line][row + 1])
            mp[line][++ row] = num[++ cnt];
        while(line + 1 <= m && !mp[line + 1][row])
            mp[++ line][row] = num[++ cnt];
        while(row - 1 > 0 && !mp[line][row - 1])
            mp[line][-- row] = num[++ cnt];
        while(line - 1 > 0 && !mp[line - 1][row])
            mp[-- line][row] = num[++ cnt];   
    }
    
    for(int i = 1;i <= m;i ++)
	{
		for(int j = 1;j <= n;j ++)
			printf("%d%c",mp[i][j],j == n ? '\n' : ' ');
	} 
	return 0;
}

1089 狼人杀-简单版 (20分)

1089 狼人杀-简单版

题目描述

以下文字摘自《灵机一动·好玩的数学》:“狼人杀”游戏分为狼人、好人两大阵营。在一局“狼人杀”游戏中, 1 1 1 号玩家说:“ 2 2 2 号是狼人”, 2 2 2 号玩家说:“ 3 3 3 号是好人”, 3 3 3 号玩家说:“ 4 4 4 号是狼人”, 4 4 4 号玩家说:“ 5 5 5 号是好人”, 5 5 5 号玩家说:“ 4 4 4 号是好人”。已知这 5 5 5 名玩家中有 2 2 2 人扮演狼人角色,有 2 2 2 人说的不是实话,有狼人撒谎但并不是所有狼人都在撒谎。扮演狼人角色的是哪两号玩家?

本题是这个问题的升级版:已知 N N N 名玩家中有 2 2 2 人扮演狼人角色,有 2 2 2 人说的不是实话,有狼人撒谎但并不是所有狼人都在撒谎。要求你找出扮演狼人角色的是哪几号玩家?

输入格式:
输入在第一行中给出一个正整数 N ( 5 ≤ N ≤ 100 ) N(5 \le N \le 100) N5N100。随后 N N N 行,第 i i i 行给出第 i i i 号玩家说的话 ( 1 ≤ i ≤ N ) (1 \le i \le N) (1iN),即一个玩家编号,用正号表示好人,负号表示狼人。

输出格式:

如果有解,在一行中按递增顺序输出 2 2 2 个狼人的编号,其间以空格分隔,行首尾不得有多余空格。如果解不唯一,则输出最小序列解 —— 即对于两个序列 A = a [ 1 ] , . . . , a [ M ] A=a[1],...,a[M] A=a[1],...,a[M] B = b [ 1 ] , . . . , b [ M ] B=b[1],...,b[M] B=b[1],...,b[M],若存在 0 ≤ k < M 0 \le k < M 0k<M 使得 a [ i ] = b [ i ] ( i ≤ k ) a[i]=b[i] (i \le k) a[i]=b[i]ik,且 a [ k + 1 ] < b [ k + 1 ] a[k+1]<b[k+1] a[k+1]<b[k+1],则称序列 A A A 小于序列 B B B。若无解则输出 No Solution。

输入样例 1:

5
-2
+3
-4
+5
+4

输出样例 1:

1 4

输入样例 2:

6
+6
+3
+1
-5
-2
+4

输出样例 2(解不唯一):

1 5

输入样例 3:

5
-2
-3
-4
-5
-1

输出样例 3:

No Solution

Solution

既然狼人和说谎的人的数量是一定的,而且仅有2个,那么不妨直接枚举狼人(或者枚举说谎的人)来判断该情况是否合法。

代码

#include <bits/stdc++.h>
using namespace std;
const int SZ = 100 + 10;
struct zt
{
	char a;
	int b;
}peo[SZ];
int n;

inline bool check(int a,int b)
{
	vector<int> liar; 
	for(int i = 1;i <= n;i ++)
	{
		if(peo[i].a == '+' && (peo[i].b == a || peo[i].b == b)) liar.push_back(i);
		if(peo[i].a == '-' && peo[i].b != a && peo[i].b != b) liar.push_back(i);
	}
	if(liar.size() != 2) return 0;
	int liarnum = 0;
	for(auto x: liar)
		if(x == a || x == b) liarnum ++;
	if(liarnum != 1) return 0;
	return 1;
} 

int main()
{
	scanf("%d",&n);
	for(int i = 1;i <= n;i ++) 
	{
		getchar();
		scanf("%c%d",&peo[i].a,&peo[i].b);
	}
	bool flag = 0;
	for(int i = 1;i < n;i ++) //枚举狼 
	{
		for(int j = i + 1;j <= n;j ++)
		{
			if(check(i,j))
			{
				printf("%d %d\n",i,j);	
				flag = 1;
				break;
			}
		}
		if(flag == 1) break;
	}
	if(!flag) printf("No Solution\n");
	return 0;
}

1094 谷歌的招聘 (20分)

1094 谷歌的招聘

题目描述

2004 年 7 月,谷歌在硅谷的 101 号公路边竖立了一块巨大的广告牌(如下图)用于招聘。内容超级简单,就是一个以 .com 结尾的网址,而前面的网址是一个 10 10 10 位素数,这个素数是自然常数 e e e 中最早出现的 10 10 10 位连续数字。能找出这个素数的人,就可以通过访问谷歌的这个网站进入招聘流程的下一步。
自然常数 e e e 是一个著名的超越数,前面若干位写出来是这样的:
e = 2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003059921... e=2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003059921... e=2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003059921... 其中粗体标出的 10 10 10 位数就是答案。

本题要求你编程解决一个更通用的问题:从任一给定的长度为 L L L 的数字中,找出最早出现的 K K K 位连续数字所组成的素数。

输入格式:

输入在第一行给出 2 2 2 个正整数,分别是 L L L(不超过 1000 1000 1000 的正整数,为数字长度)和 K K K(小于 10 10 10 的正整数)。接下来一行给出一个长度为 L L L 的正整数 N N N

输出格式:

在一行中输出 N N N 中最早出现的 K K K 位连续数字所组成的素数。如果这样的素数不存在,则输出 404 404 404。注意,原始数字中的前导零也计算在位数之内。例如在 200236 200236 200236 中找 4 4 4 位素数, 0023 0023 0023 算是解;但第一位 2 2 2 不能被当成 0002 0002 0002 输出,因为在原始数字中不存在这个 2 2 2 的前导零。

输入样例 1:

20 5
23654987725541023819

输出样例 1:

49877

输入样例 2:

10 3
2468024680

输出样例 2:

404

Solution

将字符串处理成整数,然后O( n \sqrt{n} n )判断是否为素数。
注意输出的时候直接输出字符,防止漏掉前导0。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int SZ = 1e3 + 20;
char s[SZ];

inline bool check(int x)
{
	if(x == 0 || x == 1) return 0;
	for(int i = 2;i * i <= x;i ++)
		if(x % i == 0) return 0; 
	return 1;
}

int main()
{
	int n,k;
	ll sum;
	scanf("%d%d",&n,&k);
	scanf("%s",s);
	bool flag = 0;
	for(int i = 0;i < n - k + 1; i ++)
	{	
		sum = 0;
		for(int j = i;j <= i + k - 1;j ++)
		{
			sum = sum * 10 + (s[j] - '0'); 
		}
		if(check(sum)) 
		{
			for(int j = i;j <= i + k - 1;j ++) printf("%c",s[j]);
			printf("\n");
			flag = 1;
			break;
		}
	}
	if(!flag) printf("404");
 	return 0;
}

2020.7.18

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值