题目大意:有n盏灯标号1到n,一开始1是亮的其余是暗的。然后从小到大考虑每个质数p,选择一个亮的灯x并且把所有和x距离是p的倍数的灯点亮。问最后亮多少灯并输出方案。
题解:
首先所有点的编号-1。
这样每次选择0就可以把除了1(原来是2)的所有灯点亮,因此答案至少是n-1。
首先当n<=16的时候没有n的解。当26<=n<=34的时候手玩。
否则:找两个质数p1和p2满足
,然后到p1的时候操作p1+1(原来是p1+2),到p2的时候操作p1+p2(原来是p1+p2+1)。可以证明如果存在这样的p1和p2那么显然这个合法。同时打表发现当17<=n<=25或者35<=n<=1e6的时候存在答案。(垃圾题毁我青春)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define N 1000010
using namespace std;
int p[N],c,np[N];
int main()
{
int n;scanf("%d",&n);
for(int i=2;i<=n;i++)
{
if(!np[i]) p[++c]=i;
for(int j=1;j<=c&&p[j]<=n/i;j++)
{
int x=p[j]*i;np[x]=1;
if(i%p[j]==0) break;
}
}
if(n<=16)
{
printf("%d %d\n",c,n-1);
for(int i=1;i<=c;i++) printf("1\n");
return 0;
}
printf("%d %d\n",c,n);int a=0,b=0;
if(n>=26&&n<=34)
{
for(int i=1;i<=c;i++)
if(p[i]==5) printf("13\n");
else if(p[i]==7||p[i]==17) printf("19\n");
else if(p[i]==11) printf("17\n");
else printf("1\n");
return 0;
}
for(int i=1;i<=c;i++) if(1ll*p[i]*p[i]>=n)
for(int j=i+1;j<=c&&p[i]+p[j]<n;j++)
if(p[j]%p[i]==1) { a=i,b=j;goto loop; }
loop:;
for(int i=1;i<=c;i++)
if(i==a) printf("%d\n",p[a]+2);
else if(i==b) printf("%d\n",p[a]+p[b]+1);
else printf("%d\n",1);
return 0;
}