灯 - 构造

题目大意:有n盏灯标号1到n,一开始1是亮的其余是暗的。然后从小到大考虑每个质数p,选择一个亮的灯x并且把所有和x距离是p的倍数的灯点亮。问最后亮多少灯并输出方案。
题解:
首先所有点的编号-1。
这样每次选择0就可以把除了1(原来是2)的所有灯点亮,因此答案至少是n-1。
首先当n<=16的时候没有n的解。当26<=n<=34的时候手玩。
否则:找两个质数p1和p2满足 p 1 2 >= n , p 1 < p 2 , p 1 + p 2 < n , p 2 % p 1 = 1 ,然后到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;
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/82315624