AT4299 [ABC128C] Switches题解

题目传送门


思路

灯有两种形式:一种是开,一种是关,我们自然而然的想到了二进制:用 \(1\) 代表开,用 \(0\) 代表关。这样我们就可以用 bool 类型来存下一个灯的状态。

由于这道题数据范围小,\(1 \leq N,M \leq 10\),我们可以考虑 Dfs。

怎么 Dfs 呢,可以考虑枚举每个灯泡,求出对应开关中灯的数量和,再直接算 \(\%2\) 的值。

Dfs 枚举灯泡的时间复杂度是 \(O(2^{n})\),每一次枚举灯泡中有 \(m\times n\)的循环,时间复杂度是 \(O({n\times m})\),所以总的时间复杂度是 \(O(2^nmn)\),极限情况为 \(2^{10}\times10\times10=102400\)洛谷的评测姬跑的飞快!


代码如下

//#include<bits/stdc++.h>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f,MOD=1e9+7;
#define pu putchar
#define endl puts("")
//#define int __int128
//#define int long long
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,r,l) for(int i=r;i>=l;--i)
#define me0(a); memset(a,0,sizeof a);
#define me3(a); memset(a,0x3f,sizeof a);
#define PII pair<int,int>
void read(int &n){char c,w=1;for(;48>c||c>57;c=getchar())
w=c==45?-1:1;for(n=0;47<c&&c<58;c=getchar())n=n*10+c-48;n*=w;
}void write(int x){if(x<0)pu(45),x=-x;char c[41],s=0;
for(;x;)c[s++]=x%10,x/=10;if(!s)pu(48);for(;s--;)pu(c[s]+48);
}void debug(int n){printf("\tdebug:\t"); write(n); pu('\t');}
const int MAXN=12;
int n,m;
int ans;
int num[MAXN];
int p[MAXN];
int v[MAXN][MAXN];
bool flag[MAXN];
// 进行 Dfs。
void dfs(int step){
	//如果 step 大于 n,说明已经选完了。 
	if(step>n){
		// 遍历灯泡。
		rep(i,1,m){
			int sum=0;
			rep(j,0,num[i]){
				// 如果开关亮,++sum。
				if(flag[v[i][j]]) {
					++sum;
				}
			}if(sum%2!=p[i]){// 判断满不满足条件。
				return;
			}
		}++ans;// 满足条件,++ans。
		return;
	}flag[step]=1; dfs(step+1); // 枚举灯泡的状态。
	flag[step]=0; dfs(step+1);
}main(){
	// 输入。
	read(n); read(m);
	rep(i,1,m){
		read(num[i]);
		rep(j,1,num[i]){
			read(v[i][j]);
		}
	}rep(i,1,m){
		read(p[i]);
	}dfs(1); // Dfs。
	write(ans); // 输出。
}

\(AC\) 记录(全洛谷第一最优解,欢迎打破)。

完结撒花 \(\sim\sim\sim\)

posted @ 2023-07-01 11:14  liukejie  阅读(26)  评论(0编辑  收藏  举报