T1,T3我就不说啦,反正也不会。主要想讲的是T2.
T2用了一个神奇的算法:折半搜索。
因为这个坑爹的数据范围告诉我们暴搜或是状压会TLE,而一半刚好能卡过去。
折半搜索其实跟暴搜没什么区别,就是折了半(废话)。拿这道题为例,暴搜就是在长度为2n的序列中找出所有长度为n的序列不妨设为s1, 那么剩下的就是s2,然后判断s1和翻转后的s2是否相等,复杂度O(C(n, 2n))。
折半搜索就是在前一半的序列中找出所有长度为n / 2的序列,也就是s1的前一半s1',剩下的作为s2的后一半(因为要反转)s2'。然后把这种状态,即s1' + s2'记下来,用map实现最方便。接下来我们在[n + 1, 2n]这个区间里暴搜,找到s1的后一半s1'',s2的前一半s2''(当然还要反转),为了验证两个合一块的字符串是否相等,我们只要证明s2'' + s1''是否存在过,如果存在,就说明找到了一组,ans++。时间复杂度O(C(n / 2, n) * 2)。理论上也是暴搜,却快了不少。
代码实现的时候用string最方便不过,不仅用加号就能代替strcpy,而且还自带反转函数。
代码就是两遍状压暴搜
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 #include<map> 12 #include<string> 13 using namespace std; 14 #define enter puts("") 15 #define space putchar(' ') 16 #define Mem(a, x) memset(a, x, sizeof(a)) 17 #define rg register 18 typedef long long ll; 19 typedef double db; 20 const int INF = 0x3f3f3f3f; 21 const db eps = 1e-8; 22 const int maxn = 40; 23 inline ll read() 24 { 25 ll ans = 0; 26 char ch = getchar(), last = ' '; 27 while(!isdigit(ch)) {last = ch; ch = getchar();} 28 while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();} 29 if(last == '-') ans = -ans; 30 return ans; 31 } 32 inline void write(ll x) 33 { 34 if(x < 0) x = -x, putchar('-'); 35 if(x >= 10) write(x / 10); 36 putchar(x % 10 + '0'); 37 } 38 void MYFILE() 39 { 40 #ifndef mrclr 41 freopen("string.in", "r", stdin); 42 freopen("string.out", "w", stdout); 43 #endif 44 } 45 46 int n; 47 char s[maxn]; 48 string s1, s2; 49 map<string, int> mp; 50 ll ans = 0; 51 52 int main() 53 { 54 MYFILE(); 55 n = read(); scanf("%s", s); 56 for(int i = 0; i < (1 << n); ++i) 57 { 58 s1.clear(); s2.clear(); 59 for(int j = 0; j < n; ++j) 60 if(i & (1 << j)) s1 += s[j]; 61 else s2 += s[j]; 62 reverse(s2.begin(), s2.end()); 63 mp[s1 + "#" + s2]++; //加一个字符,区分s1, s2 64 } 65 for(int i = 0; i < (1 << n); ++i) 66 { 67 s1.clear(); s2.clear(); 68 for(int j = 0; j < n; ++j) 69 if(i & (1 << j)) s1 += s[j + n]; 70 else s2 += s[j + n]; 71 reverse(s2.begin(), s2.end()); 72 ans += mp[s2 + "#" + s1]; 73 } 74 write(ans >> 1); enter; 75 return 0; 76 }