JZOJ1265.【USACO题库】2.2.4 Party Lamps派对灯

本文介绍了一个经典的IOI98竞赛题目——彩灯问题。任务是根据按钮按压次数和最终灯的状态,找出所有可能的初始灯状态组合。文章提供了详细的解题思路,包括如何优化算法以减少计算时间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

在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)上的数值和经过若干操作后所有灯的状态。写一个程序去找出所有灯最后可能的与所给出信息相符的状态,并且没有重复。

PROGRAM NAME: lamps

INPUT FORMAT

不会有灯会在输入中出现两次。

第一行: N。
第二行: C最后显示的数值。
第三行: 最后亮着的灯,用一个空格分开,以-1为结束。
第四行: 最后关着的灯,用一个空格分开,以-1为结束。

SAMPLE INPUT (file lamps.in)

10

1

-1

7 -1

在这个样例中,有10盏灯,只有1个按钮被按下。最后7号灯是关着的。

OUTPUT FORMAT

每一行是所有灯可能的最后状态(没有重复)。每一行有N个字符,第1个字符表示1号灯,最后一个字符表示N号灯。0表示关闭,1表示亮着。这些行必须从小到大排列(看作是二进制数)。

如果没有可能的状态,则输出一行’IMPOSSIBLE’。

SAMPLE OUTPUT (file lamps.out)

0000000000

0101010101

0110110110

在这个样例中,有三种可能的状态:

所有灯都关着

1,4,7,10号灯关着,2,3,5,6,8,9亮着。

1,3,5,7,9号灯关着,2, 4, 6, 8, 10亮着。

输入

输出

样例输入

样例输出

数据范围限制

首先这又是一道IOI真题~

思路:
采取暴力的思想
但直接来绝对时间爆炸
那么考虑优化:

优化1:
通过手算不难发现,无论怎么改变,都是六个一循环的
于是乎我们可以只改变六个,最后再判断整段,节省时间

上面的优化完全不够?
那么下面这个优化才是AC关键
优化2:
对于任意一个c,若它大于等于8:
为偶数就为4,否则就为5
严谨证明过程略,但这个东东一定是正确的

于是乎两个优化到手,AC轻松揣进兜~

代码(不知怎么,这段code打得很难看):

type
        arra=array[0..6]of longint;
const
        change:array[1..4,1..6]of longint=
        (
        (1,1,1,1,1,1),
        (1,0,1,0,1,0),
        (0,1,0,1,0,1),
        (1,0,0,1,0,0)
        );
var
        n,c,i,x,tot:longint;
        open,off:array[0..100]of boolean;
        ans:array[0..10000]of string;
        temp:arra;
procedure qsort(l,r:longint);
var
        i,j:longint;
        mid,t:string;
begin
        i:=l;
        j:=r;
        mid:=ans[(l+r)div 2];
        repeat
                while ans[i]<mid do inc(i);
                while ans[j]>mid do dec(j);
                if i<=j then
                begin
                        t:=ans[i];
                        ans[i]:=ans[j];
                        ans[j]:=t;
                        inc(i);
                        dec(j);
                end;
        until i>j;
        if l<j then qsort(l,j);
        if i<r then qsort(i,r);
end;
function judge(t:arra):boolean;
var
        i,j:longint;
begin
        for i:=1 to n do
        begin
                j:=i mod 6;
                if j=0 then j:=6;
                if (open[i])and(t[j]=0)or(off[i])and(t[j]=1)then exit(false);
        end;
        exit(true);
end;
procedure dfs(x:longint;fx:arra);
var
        i,j:longint;
        flag:boolean;
        st:string;
        xx:arra;
begin
        if x>c then
        begin
                if judge(fx) then
                begin
                        st:='';
                        for i:=1 to n do
                        begin
                                j:=i mod 6;
                                if j=0 then j:=6;
                                if fx[j]=1 then st:=st+'1'
                                else st:=st+'0';
                        end;
                        flag:=true;
                        for i:=1 to tot do
                        if ans[i]=st then
                        begin
                                flag:=false;
                                break;
                        end;
                        if flag then
                        begin
                                inc(tot);
                                ans[tot]:=st;
                        end;
                end;
                exit;
        end;
        for j:=1 to 4 do
        begin
                for i:=1 to 6 do
                xx[i]:=(fx[i]+change[j,i])mod 2;
                dfs(x+1,xx);
        end;
end;
begin
        read(n,c,x);
        for i:=1 to 6 do temp[i]:=1;
        while x<>-1 do
        begin
                open[x]:=true;
                read(x);
        end;
        read(x);
        while x<>-1 do
        begin
                off[x]:=true;
                read(x);
        end;
        if c>=8 then
        begin
                if c mod 2=0 then c:=4
                else c:=5;
        end;
        dfs(1,temp);
        if tot=0 then writeln('IMPOSSIBLE')
        else
        begin
                qsort(1,tot);
                for i:=1 to tot do writeln(ans[i]);
        end;
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值