UVALive 6256 LA 6256 Who wants to live forever?
题意:给出一个只含01的字符串,然后用s(i-1) xor s(i+1)的结果去更新s(i),最后问能否将原串更新成全部为0的字符串。
一拿到就觉得这应该是找规律题,经过简单的推理,可以得到这么一些结论:
1.当字符串长度为1,3,7的时候,无论原串是什么,分别最多做1,3,7次操作,总能变成全部为0的串(YY:只要字符串的长度为2^n-1,无论原串是什么,总能变成全部为0的串)
2.当字符串长度为偶数时,除非原串本身全为0,否则不可能将原串更新为全部为0的串(这个能证出来,倒着推一下就行了,给出一个长度为偶数且全为0的串,向上推一个可行的状态,让它不仅含有1而且还可以变成全部为0的,这是不可能的)
3.当字符串长度为4n+1时,除非原串本身全为0或者为10101…………010101这样以1开始和结尾,中间01间隔的这样一种形式,否则不可能将原串更新为全部为0的串(还是跟上面一样倒推,可以推出来)
4.当字符串长度为4n+3时,状态就比较多了,显然对于4n+1的所有情况是成立的,但是由10101…………010101这样的串,还可以往上推。这好像就没什么办法了。没办法就暴力打表(当然也是倒着推来打的表),打出来看下有什么规律。。但是打出来从字符串本身来看,真的找不到什么规律。但是有一个发现,当字符串长度n=11,19的时候,可行解一共是8个,当n=23的时候,可行解突然达到了128个。再然后,可以推出来(不是看出来,当然看也能看出来),所有长度为11的可行串,在4,8这两个位置上必须为0,且1-3和5-7这两个区间是关于4位置对称的,5-7和9-11这两个区间是关于8这个位置对称的,大概就是这样一种情况:acb0bca0acb。结合刚才的两点,又可以YY了:可行解一定是关于某些位置对称的,n=11,19的时候,可行解数是8=2^3,n=23的时候,可行解数=128=2^7,继续YY,长度为11的时候,可行解的只有abc的取值决定,abc各有两个取值,结果就是2的3次=8。要是这样的话,n=23的时候,应该关于8,16这两个位置对称,可行解应该是这样一种形式:abcdefg0gfedcba0abcdefg,可行解的只有abcdefg的取值决定,abcdefg各有两个取值,结果就是2的7次=128。那么这个对称的位置的取值究竟是由什么决定的,继续YY。(11+1)%(2^2)=0,(19+1)%(2^2)=0,(23+1)%(2^3)=0,也就是说,当字符串长度=4n+3的时候,要找一个最大的k,使得(4n+3+1)%(2^k)=0,那么这些对称的位置就是所有的0<(2^k)*t<4n+3(t为整数)的位置。
以上是我们YY本题的全部过程。用这样的做法去交能AC也说明了这些YY的结果都是正确的。本题我们队集体YY了一小时,最后因为我的一个失误,在比赛的最后时刻没有A,就差了一行。。要是正式比赛出现这样的情况,是要吐血的。
看到标程,彻底Orz了。。不管字符串长度是多少,他只用到了我上面写的第4条YY的那些规则就搞定了,不过后来我想想也对,只要满足第四条的对称规则就行。
贴两份代码,一份自己写的,一份标程的
1 #include <cstdio> 2 #include <cstring> 3 char S[200020]; 4 int main(){ 5 int T,len; 6 scanf("%d",&T); 7 while(T--){ 8 scanf("%s",S); 9 len = strlen(S); 10 if((len&(len+1)) == 0){ 11 puts("DIES"); 12 continue; 13 } 14 if((len&1) == 0){ 15 bool flag = 1; 16 for(int i = 0;i < len;i++){ 17 if(S[i] - '0' == 1){ 18 flag = 0; 19 break; 20 } 21 } 22 if(flag) puts("DIES"); 23 else puts("LIVES"); 24 continue; 25 } 26 if(len % 4 == 1){ 27 bool flag = 1; 28 for(int i = 0;i < len;i++){ 29 if(S[i] - '0' == 1){ 30 flag = 0; 31 break; 32 } 33 } 34 if(flag){ 35 puts("DIES"); 36 continue; 37 } 38 flag = 1; 39 for(int i = 0;i < len;i++){ 40 if((i&1) == 0 && S[i] - '0' != 1){ 41 flag = 0; 42 break; 43 } 44 if((i&1) == 1 && S[i] - '0' != 0){ 45 flag = 0; 46 break; 47 } 48 } 49 if(flag) puts("DIES"); 50 else puts("LIVES"); 51 continue; 52 } 53 if(len % 4 == 3){ 54 bool flag = 1; 55 for(int i = 0;i < len;i++){ 56 if(S[i] - '0' == 1){ 57 flag = 0; 58 break; 59 } 60 } 61 if(flag){ 62 puts("DIES"); 63 continue; 64 } 65 flag = 1; 66 int k = 1; 67 int tmp = len+1; 68 while((tmp&1) == 0){ 69 k *= 2; 70 tmp >>= 1; 71 } 72 for(int i = k-1;i < len;i = i+k){ 73 if(S[i] - '0' != 0){ 74 flag = 0; 75 break; 76 } 77 for(int j = 1;j < k;j++){ 78 if(S[i-j] != S[i+j]){ 79 flag = 0; 80 } 81 } 82 } 83 if(flag) puts("DIES"); 84 else puts("LIVES"); 85 } 86 } 87 return 0; 88 }
1 // CERC 2012 2 // Problem B: Who wants to live forever? 3 // O(n) solution 4 // Author: Arkadiusz Pawlik 5 6 #include <iostream> 7 #include <string> 8 #include <algorithm> 9 using namespace std; 10 11 bool die(string s) { 12 s += "0"; 13 int n = s.size(); 14 int l = ((n ^ (n-1)) + 1) / 2; 15 int cnt = n / l; 16 cout<<"n="<<n<<" l="<<l<<endl; 17 cout<<"cnt="<<cnt<<endl; 18 for (int i = 1; i < cnt; ++i) { 19 for (int k = 0; k < l-1; ++k) { 20 if (s[i*l+k] != s[i*l-2-k]) return false; 21 } 22 cout<<"caca:"<<s[i*l-1]<<endl; 23 if (s[i*l-1] != '0') return false; 24 } 25 return true; 26 } 27 /* 28 string ft(string s) { 29 for (int i = 0; i < s.size(); ++i) { 30 if (i % 3 == 2) continue; 31 s[i] = (s[i] == '1') ? '0' : '1'; 32 } 33 return s; 34 } 35 */ 36 int main() { 37 int n; 38 cin >> n; 39 while(n--) { 40 string s; 41 cin >> s; 42 if (die(s)) cout << "DIES" << endl; 43 else cout << "LIVES" << endl; 44 } 45 }