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); // 输出。
}