Description
在IOI98的节日宴会上,我们有N(10<=N<=100)盏彩色灯,他们分别从1到N被标上号码。 这些灯都连接到四个按钮: 按钮1:当按下此按钮,将改变所有的灯:本来亮着的灯就熄灭,本来是关着的灯被点亮。 按钮2:当按下此按钮,将改变所有奇数号的灯。 按钮3:当按下此按钮,将改变所有偶数号的灯。 按钮4:当按下此按钮,将改变所有序号是3*K+1(K>=0)的灯。例如:1,4,7... 一个计数器C记录按钮被按下的次数。 当宴会开始,所有的灯都亮着,此时计数器C为0。 你将得到计数器C(0<=C<=10000)上的数值和经过若干操作后所有灯的状态。写一个程序去找出所有灯最后可能的与所给出信息相符的状态,并且没有重复。
Input
不会有灯会在输入中出现两次。 第一行: N。 第二行: C最后显示的数值。 第三行: 最后亮着的灯,用一个空格分开,以-1为结束。 第四行: 最后关着的灯,用一个空格分开,以-1为结束。
Output
每一行是所有灯可能的最后状态(没有重复)。每一行有N个字符,第1个字符表示1号灯,最后一个字符表示N号灯。0表示关闭,1表示亮着。这些行必须从小到大排列(看作是二进制数)。 如果没有可能的状态,则输出一行'IMPOSSIBLE'。
Sample Input
10 1 -1 7 -1 /*在这个样例中,有10盏灯,只有1个按钮被按下。最后7号灯是关着的。*/
Sample Output
0000000000 0101010101 0110110110 /*在这个样例中,有三种可能的状态: 所有灯都关着 1,4,7,10号灯关着,2,3,5,6,8,9亮着。 1,3,5,7,9号灯关着,2, 4, 6, 8, 10亮着。*/
每个的灯最开始的时候是亮着的,现在按了C次开关,但是不知道每次按的是哪一个,让求按到最后每盏灯可能的状态
思路:
现在一共有4种按开关的方式,而每一种其实就只有开/关两种状态(因为同一个开关按3次和按一次效果是一样的),所以我们可以直接枚举每一种按法,然后判断是否符合条件就行了
这里我优化了一下,设了一个flag变量,然后按1开关(全部取反)就将flag取反,最后灯的状态可以用当前灯的状态^flag得到(相同为0不同为1,flag为0的话异或不变,flag为1的话异或取反)
#include <map>
#include <queue>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lowbit(a) (a&(-a))
#define _mid(a,b) ((a+b)/2)
#define _mem(a,b) memset(a,0,(b+3)<<2)
#define fori(a) for(int i=0;i<a;i++)
#define forj(a) for(int j=0;j<a;j++)
#define ifor(a) for(int i=1;i<=a;i++)
#define jfor(a) for(int j=1;j<=a;j++)
#define mem(a,b) memset(a,b,sizeof(a))
#define IN freopen("in.txt","r",stdin)
#define OUT freopen("out.txt","w",stdout)
#define IO do{\
ios::sync_with_stdio(false);\
cin.tie(0);\
cout.tie(0);}while(0)
using namespace std;
typedef long long ll;
const int maxn = 1500+10;
const int INF = 0x3f3f3f3f;
const int inf = 0x3f;
const double EPS = 1e-7;
const double Pi = acos(-1);
const int MOD = 1e9+7;
bool a[105];
int ON[105];
int OFF[105];
char bufs[105];
string res[1<<4|1];
bool flag;
int c,con,cof;
int n;
bool getbit(int x,int i) { //判断i号开关是否按下
return (x>>i)&1;
}
void change(int x) {
if(getbit(x,0)==1) //按了1号开关
flag = true;
ifor(n) {
if(getbit(x,1)&&i%2) //按了2号开关
a[i] = !a[i];
if(getbit(x,2)&&i%2==0)//按了3号开关
a[i] = !a[i];
if(getbit(x,3)&&(i-1)%3==0)//按了4号开关
a[i] = !a[i];
}
}
bool juge() {
fori(con)
if(!(a[ON[i]]^flag))
return false;
fori(cof)
if(a[OFF[i]]^flag)
return false;
return true;
}
int main() {
IO;
//IN;
con = cof = 0;
int cnt = 0;
cin >> n >> c;
ifor(n)
a[i] = 1;
do {
cin >> ON[con];
} while(ON[con++]!=-1);
do {
cin >>OFF[cof];
} while(OFF[cof++]!=-1);
cof--,con--;
fori(1<<4) {
//这里是从0000到1111遍历,能找出开关所有状态
int fun = __builtin_popcount(i);
//编译器内置函数,用于求i的二进制数中'1'的个数
if(fun%2==c%2&&fun<=c) { //奇偶性相等且次数必须少于或等于按开关的次数
flag = false;
change(i);
if(juge()) {
int buf = 0;
ifor(n)
bufs[buf++] = (a[i]^flag)+'0';
bufs[buf] = 0;
res[cnt++] = bufs;
}
change(i);
}
}
if(cnt){
sort(res,res+cnt);
fori(cnt)
cout << res[i] << endl;
}
else
cout <<"IMPOSSIBLE" << endl;
return 0;
}