• 【XSY1522】灯 乱搞


    题目大意

    ​  (n)盏灯排成一列,标号(1)(n),一开始标号为(1)的灯亮着。

    ​  现在依次对于(2)~(n)的每一个质数(p_i),指定一盏亮着的灯(a_i),点亮所有标号为(a_ipm kp_i)的灯。

      输出任意一种方案即可

    ​  (nleq100000)

    题解

    ​  我们可以把灯的编号减(1),变成(0)~(n-1)

    ​  先用线性筛把质数筛出来

    ​  如果对于每一个质数都指定编号(0)的灯,就可以把除了(1)之外的所有灯点亮。

    ​  所以我们的目标是点亮(1)号灯

    ​  我们要找两个质数(p_1,p_2),满足(p_1|p_2-1,p_1^2geq n,p_2^2geq n,p_1+p_2leq n-1),然后就可以给(p_1)指定(p_1+1),给(p_2)指定(p_1+p_2)。因为所有偶数都在(p=2)时被点亮了,所以这样就可以把全部灯点亮了。

    ​  但是我们会发现n比较小时这个方法有时候会找不到答案,我们只需要写一个暴搜把(nleq50)的情况全部搜出来。

    ​  我也不知道第(55)行的那个剪枝是不是对的反正能搜出一组解。

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<ctime>
    #include<utility>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    int p[1000010];
    int b[1000010];
    int cnt;
    int a1[1000010];
    int a2[1000010];
    int a[1000010];
    int cnt1,cnt2;
    int ans[1000010];
    int c[1000010];
    int d[1000010];
    int n;
    int tcnt;
    void dfs(int x)
    {
    	if(x>cnt)
    	{
    		int i;
    		for(i=1;i<=n;i++)
    			if(!a[i])
    				return;
    //		printf("printf("%d %d\n",tcnt,n);
    //		for(i=1;i<=tcnt;i++)
    //			printf("%d\n",ans[i]);
    //		printf("");");
    		printf("%d %d
    ",tcnt,n);
    		for(i=1;i<=tcnt;i++)
    			printf("%d
    ",ans[i]);
    		exit(0);
    	}
    	int i,j;
    	for(i=1;i<=n;i++)
    		if(a[i])
    		{
    			int s=0;
    			for(j=i;j<=n;j+=p[x])
    			{
    				s+=!a[j];
    				a[j]++;
    			}
    			for(j=i-p[x];j>=1;j-=p[x])
    			{
    				s+=!a[j];
    				a[j]++;
    			}
    			ans[x]=i;
    			if(s)
    				dfs(x+1);
    			for(j=i;j<=n;j+=p[x])
    				a[j]--;
    			for(j=i-p[x];j>=1;j-=p[x])
    				a[j]--;
    		}
    }
    int main()
    {
    //	freopen("light.in","r",stdin);
    //	freopen("light.out","w",stdout);
    	scanf("%d",&n);
    	memset(b,0,sizeof b);
    	int i,j;
    	cnt=0;
    	for(i=2;i<=n;i++)
    	{
    		if(!b[i])
    			p[++cnt]=i;
    		for(j=1;j<=cnt&&i*p[j]<=n;j++)
    		{
    			b[i*p[j]]=1;
    			if(i%p[j]==0)
    				break;
    		}
    	}
    	tcnt=cnt;
    	if(n<=50)
    	{
    		memset(a,0,sizeof a);
    		a[1]=1;
    		if(p[cnt]==n)
    		{
    			ans[cnt]=1;
    			cnt--;
    		}
    		dfs(1);
    		printf("%d %d
    ",tcnt,n-1);
    		for(i=1;i<=tcnt;i++)
    			printf("1
    ");
    		return 0;
    	}
    	printf("%d ",tcnt);
    	if(p[cnt]==n)
    	{
    		ans[cnt]=1;
    		cnt--;
    	}
    	n--;
    	memset(a,0,sizeof a);
    	int cnt3=0;
    	for(i=1;i<=cnt;i++)
    	{
    		if(ll(p[i])*p[i]<=n)
    			a1[++cnt1]=p[i];
    		else
    		{
    			a2[++cnt2]=p[i];
    			d[++cnt3]=p[i];
    		}
    		ans[i]=1;
    	}
    	for(i=1;i<=cnt1;i++)
    	{
    		ans[i]=1;
    		for(j=a1[i];j<=n;j+=a1[i])
    			a[j]++;
    	}
    	for(i=1;i<=cnt2;i++)
    		c[a2[i]-1]=i;
    	int x=0;
    	for(i=cnt2;i>=1;i--)
    	{
    		for(j=a2[i];j<=n;j+=a2[i])
    			if(c[j]&&a2[i]+j<=n-2)
    			{
    				x=i;
    				ans[i+cnt1]=a2[i]+2;
    				ans[c[j]+cnt1]=a2[i]+j+2;
    				break;
    			}
    		if(x)
    			break;
    	}
    	printf("%d
    ",n+1);
    	for(i=1;i<=tcnt;i++)
    		printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    点分治练习
    PKU-2723 Get Luffy Out(2-SAT+二分)
    tarjan求割点与割边
    tarjan缩点练习 洛谷P3387 【模板】缩点+poj 2186 Popular Cows
    数算日子荣耀神
    《JavaScript DOM编程艺术》笔记
    CSS链接的样式a:link,a:visited,a:hover,a:active
    chrome调试技巧--持续更新
    CSS文字大小单位PX、EM的区别
    【转】如何成为一名优秀的web前端工程师(前端攻城师)?
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8510035.html
Copyright © 2020-2023  润新知