EOJ Monthly 2018.9 (based on Trial Round #3) D.素数子序列(构造+数论)

题目

有一个长度为 n 的序列 a1,a2,…,an,某些位置已经固定 (ai>0),其他位置允许乱填 (ai=0)。

现求一种填法,使得填完之后,序列的任意连续子串的和都是质数。换句话说,对于一切 1≤l≤r≤n,al+al+1+⋯+ar 是质数。

n<=1e5,0<=ai<=1e9,有解输出解,无解输出Impossible

思路来源

https://acm.ecnu.edu.cn/blog/entry/239/?tdsourcetag=s_pctim_aiomsg

题解

先看是否需要填,如果不需要填再判是不是质数

①n==1时,如果不需要填就判,否则填

②n==2时,两个奇素数之和必为偶数,不可取,故必有一个是2

然后暴力讨论a[1]和a[2]是不是需要填,如果不需要填是不是有一个是2

③n==3时,由于两个奇素数不能挨在一起,且(奇,2,奇)的填法会使长度为3的串和为偶数,

故只有(2,奇素数,2)的填法,注意到若填的是x,则需分别判断x,x+2,x+4是不是素数

此处由三胞胎素数定理(形如(p,p+2,p+4)的素数三元组只能是3,5,7)

由于三者模3的余数不同,必有且仅有一个可以被3整除,

若令三者均为素数,只有可能被整除的一个是3,剩余二者恰为5和7

④n>=4时,注意到对任意长度为3的子串只能填(2,奇,2)

所以当前三位填(2,奇,2)的时候,第四位只能填奇素数,

故形成了(2,奇,2,奇)的局面,存在长度为3的子串为(奇,2,奇)的局面,故Impossible

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
typedef long long ll; 
int n,a[maxn];
int b[]={0,2,3,2};
bool check(int x)
{
	if(x==1)return 0;
	for(int i=2;i*i<=x;++i)
	if(x%i==0)return 0;
	return 1;
}
void solve(int n)
{
	if(n==1)
	{
		if(!a[1])puts("2");
		else if(check(a[1]))printf("%d\n",a[1]);
		else puts("Impossible");
	}
	if(n==2)//四种情况 
	{
		if(a[1]&&a[2])
		{
			if(check(a[1])&&check(a[2])&&check(a[1]+a[2]))
			printf("%d %d\n",a[1],a[2]);
			else puts("Impossible");
		}
		else if(!a[1]&&!a[2])puts("2 3");
		else if(!a[1]&&a[2])
		{
			if(a[2]==2)puts("3 2");
			else if(check(a[2])&&check(a[2]+2))printf("%d %d\n",2,a[2]);
			else puts("Impossible");
		}
		else 
		{
			if(a[1]==2)puts("2 3");
			else if(check(a[1])&&check(a[1]+2))printf("%d %d\n",a[1],2);
			else puts("Impossible");
		} 
	}
	if(n==3)//只有2 3 2一组解 
	{
		bool flag=1;
		for(int i=1;i<=3;++i)
		{
			if(!a[i])continue;
			if(b[i]!=a[i])flag=0;
		}
		if(!flag)puts("Impossible");
		else puts("2 3 2");
	}
	if(n>=4)puts("Impossible");
} 
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
	scanf("%d",&a[i]);
	solve(n);
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/89285244