洛谷 P1468 [USACO2.2]派對燈 Party Lamps
題目描述
在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‘。
輸入輸出樣例
輸入樣例#1:10 1 -1 7 -1輸出樣例#1:
0000000000 0101010101 0110110110
說明
在這個樣例中,有三種可能的狀態:
所有燈都關著
1,4,7,10號燈關著,2,3,5,6,8,9亮著。
1,3,5,7,9號燈關著,2, 4, 6, 8, 10亮著。
翻譯來自NOCOW
USACO 2.2
【分析】
又是一道很有意思的題,懶得打題解了就搬一個講得最詳細的來吧。
··· 以下是nocow思路:
每個按鈕按2次和沒按效果是一樣的。所以每個按鈕或者按或者不按,一共有2^4=16種狀態。枚舉每個按鈕是否按下,然後生成結果,排序輸出即可(註意判重)。
另外燈1和燈7,2和8,3和9...是一樣的因此當N>=6時只需處理前6個,排序時轉換為10進制數, 輸出時反復輸出前6個的狀態.
深究:
這道題如果深究的話會變得非常簡單, 但是提前聲明,如果對這道題興趣不大,或者是初學者,建議跳過, 剛才的分析已經足以過這道題。 我們現在記不按按鈕,以及按下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種按法。
【代碼】
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int a[10][10]={{}, {0, 1, 1, 1, 1, 1, 1}, {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 1, 1, 1, 0}, {0, 0, 1, 0, 1, 0, 1}, {0, 0, 1, 1, 0, 1, 1}, {0, 1, 0, 0, 1, 0, 0}, {0, 1, 0, 1, 0, 1, 0}, {0, 1, 1, 0, 0, 0, 1}}; 5 int n, c, op[10], cl[10], x; 6 bool flag; 7 8 void init() { 9 cin >> n >> c; 10 c=min(3, c); 11 memset(op, 0, sizeof(op)); 12 memset(cl, 1, sizeof(cl)); 13 while (scanf("%d", &x)==1) { 14 if (x==-1) 15 break; 16 op[x%6?x%6:6]=1; 17 } 18 while (scanf("%d", &x)==1) { 19 if (x==-1) 20 break; 21 cl[x%6?x%6:6]=0; 22 } 23 } 24 25 void check(int t) { 26 for (int i=1;i<=6;++i) 27 if ((op[i] && !a[t][i]) || (!cl[i] && a[t][i])) 28 return; 29 flag=true; 30 for (int i=1;i<=n;++i) 31 printf("%d", a[t][i%6?i%6:6]); 32 printf("\n"); 33 } 34 35 void sovle() { 36 if (c==0) 37 check(1); 38 else if (c==1) 39 check(2), check(4), check(5), check(7); 40 else if (c==2) 41 check(2), check(3), check(4), check(6), check(7), check(8), check(1); 42 else 43 check(2), check(3), check(4), check(5), check(6), check(7), check(8), check(1); 44 if (!flag) 45 cout << "IMPOSSIBLE" << endl; 46 } 47 48 int main() { 49 init(); 50 sovle(); 51 }
洛谷 P1468 [USACO2.2]派對燈 Party Lamps