1. 程式人生 > >P1468 派對燈 Party Lamps

P1468 派對燈 Party Lamps

大佬想法太巧妙了,拿過來膜一下

思路:一個燈按1次和按3次其實是沒有任何區別的,按2次和不按也是沒有任何區別的,

所以當每一種方案的奇偶性相同的時候,實質上是一樣的,所以每一種方案只有按奇數次與偶數次兩種選擇,

同時還需要滿足總按燈次數的奇偶性,同事還要滿足題目一開始預設的需求,仔細想了一番之後發現,最多最多也就只有2*2*2*2=16中選擇

按下1,2,3,4按鈕分別O,①,②,③,④, 那麼,按下3,4,可以記為③④,

以此類推, 我們發現一個問題,那就是①,②,③之間微妙的關係, ①②=③,而②③=①,①③=②(可以自己試試),

於是我們知道,①②③也相當與不按,即相差3的倍數也可互相轉換;

所以,所謂前四個的16種按法其實只有8種, 分別為:O,①,②,③,④,①④,②④,③④;

然後討論c, 由於當c>4時,均可化為當c<=4的情況, 所以我們先討論當c<=4的情況,

當c=0時,只有一種O;

當c=1時,四種:①,②,③,④;

當c=2時,除了④均可(可以自己想想);

當c=3時,由於3-1=2,所以c=1的情況都滿足,而在c=2中,把所有有前三類的展開,如①④變為②③④, 可知滿足c=2的同時滿足c=3,所以c=3其實是c=2和c=1的並集,即所有按法均可。

當c=4時,由於4-1=3(①②③相當於不按),且4-2=2,由上,c=4也是所有按法均可。

當c>4時,我先有一個引理:對於任意的正整數n>1,均可寫成n=2*p+3*q(p,q為非負整數)的形式, 證明如下:若n為偶數,必然成立,若n為奇數,必然大於2,則n-3必為非負偶數,得證。 由這個引理我們可以知道,任意c>4均可寫成,c=2*p+3*q+3(p,q為非負整數)的形式,而可知, 對於兩個相同的按鍵,以及情況①②③(按鍵三次),均相當於不按,所以任意c>4均可化歸為c=3的情況, 即當c>4時,所有按法均可。

綜上所述,

當c=0時,只有一種O;

當c=1時,四種:①,②,③,④;

當c=2時,除了④均可;

當c>2時,所有按法均可。

所以, 只有四種情況,8種按法。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll ,ll > P;
#define  Max  ll(1000000009)
#define INF 0xf3f3f3f
int n,c,num,num1,num2;
int a1[110],a2[110];
bool a[110];
string s[8];
set<string> q;
bool ok(string x) {
	for(int i=1; i<=num1; i++)
		if(x[a1[i]]=='0')
			return 0;
	for(int i=1; i<=num2; i++)
		if(x[a2[i]]=='1')
			return 0;
	return 1;
}
int main() {
	scanf("%d",&n);
	scanf("%d",&c);
	num1=0,num2=0,num=0;
	int x;
	while(~scanf("%d",&x)&&x!=-1)
		a1[++num1]=x-1;//liang
	while(~scanf("%d",&x)&&x!=-1)
		a2[++num2]=x-1;//bu liang
	for(int i=1; i<=n; i++) {
		s[0]+='1',s[1]+='0';
		if(i%2)
			s[2]+='0',s[3]+='1';
		else
			s[3]+='0',s[2]+='1';
		if(i%3==1)
			s[4]+='0',s[5]+='1';
		else
			s[4]+='1',s[5]+='0';
	}
	s[6]=s[2];
	s[7]=s[3];
	for(int i=1; i<=n; i++) {
		if(i%3==1) {
			if(s[6][i-1]=='0')
				s[6][i-1]='1';
			else
				s[6][i-1]='0';
			if(s[7][i-1]=='0')
				s[7][i-1]='1';
			else
				s[7][i-1]='0';
		}
	}
	if(c==0) {
		if(ok(s[0]))
			cout<<s[0]<<endl;
		else
			printf("IMPOSSIBLE\n");
		return 0;
	}
	if(c==1) {
		bool flag=0;
		for(int i=1; i<=4; i++)
			if(ok(s[i]))
				flag=1,q.insert(s[i]);

		if(!flag) {
			printf("IMPOSSIBLE\n");
			return 0;
		}
		set<string>::iterator it=q.begin();
		for(; it!=q.end(); it++)
			cout<<*it<<endl;
		return 0;
	}
	bool flag=0;
	for(int i=0; i<8; i++) {
		if(c==2&&i==4)
			continue;
		if(ok(s[i]))
			flag=1,q.insert(s[i]);
	}
    
	if(!flag) {
		printf("IMPOSSIBLE\n");
		return 0;
	}
	set<string>::iterator it=q.begin();
	for(; it!=q.end(); it++)
		cout<<*it<<endl;
	return 0;
}