SGU 170 解题手记
2007 解题报告 Popularity: 1%
把二进制数10换成01可以让10异或11,一个二进制数中相邻的两位如果不同,可以对应的异或0……0110……0,就可以把这两位换个位置。异或是个很好的运算,满足交换律和结合律,而且若有a xor b=c,则有a xor c=b,b xor c=a。
把输入的字符串转化成二进制串,源串和目标串异或就得到转化所需的0……0110……0操作序列的异或结果,把这个结果拆成操作序列就行了。由于操作序列的顺序不影响异或结果,所以从高位往低位拆就行了。拆不出来的,就是无解。
Submit 1: WA on 4。不仅拆不出来无解,拆得出来也可能无解。比如:
++++ ----
就可以拆出来,但显然是无解的。
Submit 2: WA on 4。算法是错误的。只知道异或结果是无法把操作序列拆分出来的,比如:1100到0011需要4个操作:0110,1100,0011,0110,这四个操作中有两个重复的,他们异或结果为0,就导致了无法被拆分出来。
任意两个不同的位都可以通过异或的方式交换,异或0……010……010……0就可以,而这个数可以拆成若干个0……0110……0。想来可以贪心,从源串左边开始,找到一对不同且各自与目标串相反的位,异或一下0……010……010……,然后再找,一直找到最后,如果源串不能变成目标串,那就无解。
Submit 3: AC。
后记:其实这题做起来完全没有必要牵扯到二进制和异或,但多想想总归是有益的。做题的意义不在于最后那个AC多么好看,而在于从看题开始到AC的所感所思。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | //AC #include <iostream> #include <string> using namespace std; int main() { bool chain1[5000],chain2[5000]; int n,c(0); string ts; cin>>ts; n=ts.length(); for (int i(0);i<n;++i) chain1[i]=ts[i]=='+'; cin>>ts; if (ts.length()-n) { cout<<-1<<endl; return 0; } for (int i(0);i<n;++i) chain2[i]=ts[i]=='+'; bool find(false); for (int i(0);i<n-1;++i) if (chain1[i]!=chain2[i]) { find=false; for (int j(i+1);j<n;++j) if (chain1[j]!=chain1[i] && chain1[j]!=chain2[j]) { find=true; c+=j-i; chain1[j]^=1; break; } if (!find) { cout<<-1<<endl; return 0; } } cout<<c<<endl; return 0; } |
- http://www.briefdream.com/sgu-170/
- Tags:SGU, 二进制, 字符串, 异或, 算法, 贪心
- (0)comments | leave a reply
- Trackback URI