题解:CF1909E Multiple Lamps

CF1909E 题解

题面

原题传送门

思路

首先,我们考虑一个灯最后亮着的条件是什么。对于一个灯的编号为 light,当且仅当按下的数列中可以被 light 整除的数的个数为奇数的时候灯会亮着。

于是很自然的想到一个很经典的结论:当且仅当一个数为完全平方数时,其因子个数为奇数。

于是就可以考虑把所有的灯都开起来,最终剩下亮着的必然是编号为完全平方数的灯,而个数是 n 的,而这个数在 n20 时是小于等于 n5 的,于是暴力考虑 n19 的情况即可。

继续考虑可以发现,当 n4 的时候也是无解的,因为要求最终不亮灯,而题目中说开关可以是认为最后同时按下,所以,必然至少亮着一个灯,故可以直接判断无解。

对于 5n19 的情况,会发现 n 很小,可以考虑将按灯的状态压成二进制,要是有按灯的话,哪一位就为 1,否则为 0,可以发现 219 还是能接受的,所以就可以预处理,爆搜每一种按灯状态,算出对应的按过灯之后的状态(也是压成二进制,亮着为 1,否则为 0),判断是否合法(其中 1 的个数是否小于 n5),最后再对于每一个限制进行判断,详情见代码。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector> 
#define ll long long
using namespace std;
const int MN=200005;
ll T,n,m,u[MN],v[MN];
vector<ll>ans[20];
void write(ll n){if(n>9)write(n/10);putchar(n%10+'0');}
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
ll gs(ll x){ll res=0;while(x){x&=(x-1);/*移除最后一个1*/res++;}return res;}//计算二进制中1的个数 
void solve(){
	for(ll i=0; i<ans[n].size(); i++){//枚举所有按灯情况 
		bool flag=false;
		for(ll j=1; j<=m; j++) if(ans[n][i]>>(u[j]-1)&1&&!(ans[n][i]>>(v[j]-1)&1)){//判断是否满足给的要求 
			flag=true;//不满足就直接结束 
			break;
		} 
		if(!flag){//满足条件 
			write(gs(ans[n][i]));putchar('\n');
			for(ll j=1; j<=n; j++) if(ans[n][i]>>(j-1)&1) write(j),putchar(' ');
			putchar('\n');return; 
		}
	}
	printf("-1\n");
}
int main(){
	for(ll i=5; i<=19; i++)/*枚举位数*/for(ll s=1; s<(1<<i); s++){//因为必须至少亮一盏灯,所以枚举的状态从1开始,注意这里的状态不是灯的,而是按灯的状态。 
		ll num=0;//记录按灯之后灯的状态 
		for(ll j=1; j<=i; j++) if((s>>(j-1))&1)/*第j盏灯是亮的,因为s是从第0位开始的,所以用j-1*/for(ll k=j; k<=i; k+=j) num^=(1<<(k-1));//k-1同前
		if(gs(num)<=i/5) ans[i].push_back(s);//这是一种合法的情况 
	}
	T=read();while(T--){//多组数据 
		n=read();m=read();
		for(int i=1; i<=m; i++) u[i]=read(),v[i]=read();
		if(n<=4){printf("-1\n");continue;}//无解情况直接输出-1
		if(n>=20){//保证有解,输出把所有灯都点亮的方案 
			write(n);putchar('\n');//输出方案个数 
			for(ll i=1; i<=n; i++) write(i),putchar(' ');//每个灯都点亮
			putchar('\n');continue; 
		}
		solve();
	}
	return 0;
}
posted @   naroto2022  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示
魔非魔,道非道,善恶在人心。欲非欲,情非情,姻缘由天定。