题目描述
在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)上的数值和经过若干操作后某些灯的状态。写一个程序去找出所有灯最后可能的与所给出信息相符的状态,并且没有重复。
输入输出格式
输入格式:
不会有灯会在输入中出现两次。
第一行: N。
第二行: C最后显示的数值。
第三行: 最后亮着的灯,用一个空格分开,以-1为结束。
第四行: 最后关着的灯,用一个空格分开,以-1为结束。
输出格式:
每一行是所有灯可能的最后状态(没有重复)。每一行有N个字符,第1个字符表示1号灯,最后一个字符表示N号灯。0表示关闭,1表示亮着。这些行必须从小到大排列(看作是二进制数)。
如果没有可能的状态,则输出一行’IMPOSSIBLE’。
做题思路
我开始真的太天真了,以为这个是一个纯粹的搜索,(肯定是我水题做多了,皮了),结果一看数据范围0<=C<=10000。。
这题模拟怎么搞得出???,于是,在不知道怎么办后,我诚心地去看了大佬的解释,知道了一个按钮按了2次后等于没按(第一位发现的大佬绝对是个天才!!!)
然鹅。。。。还是搞不出。。。。
AC思路
我们已经提到,每个按钮按两次都会回归原点,这就意味着其实对于每个按钮,我们只有按与不按两种选择,所以我们只需要枚举各按钮状态,然后判断是否满足条件,既可以得到答案;
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,lk;
int k[10000];
int a[100][400];
int t=0;
int chu()
{ //1为按,0为不按;
for(int i=0;i<=1;i++)//按钮1
for(int j=0;j<=1;j++)//按钮2
for(int kk=0;kk<=1;kk++)//按钮3
for(int z=0;z<=1;z++)//按钮4
if((i+j+kk+z)%2==m%2&&i+j+kk+z<=m)//既要满足次数相同,也要满足不超时;
{
t++;
for(int u=1;u<=n;u++)
a[t][u]=1;//初始化;
if(i)
for(int u=1;u<=n;u++)
a[t][u]=1-a[t][u];
if(j)
for(int u=1;u<=n;u+=2)
a[t][u]=1-a[t][u];
if(kk)
for(int u=2;u<=n;u+=2)
a[t][u]=1-a[t][u];
if(z)
for(int u=1;u<=n;u+=3)
a[t][u]=1-a[t][u];
for(int u=1;u<=n;u++)
if((a[t][u]==k[u])||(a[t][u]==k[u])||k[u]==-1);//剔除不满足条件的;
else
{
t--;
break;
}
}
if(!t)cout<<"IMPOSSIBLE"<<endl;//没有就输出impossible;
for(int ll=1;ll<=n;ll++)
for(int i=1;i<=t-1;i++)
for(int j=1;j<=t-i;j++)
for(int k=1;k<=n;k++)
if(a[j][k]==a[j+1][k])
continue;
else if(a[j][k]<a[j+1][k])break;
else
{
swap(a[j],a[j+1]);
break;
}//按照二进制排序;
for(int i=1;i<=t;i++,cout<<endl)
for(int j=1;j<=n;j++)
printf("%d",a[i][j]);//输出;
return 0;
}
int main()
{
int ah,b;
cin>>n;
cin>>m;
for(int i=1;i<=n;i++)k[i]=-1;
while(ah!=-1)
{
cin>>ah;
if(ah==-1)break;
k[ah]=1;
}
while(1)
{
cin>>b;
if(b==-1)break;
k[b]=0;//条件数组;
}
chu();
}