• 2018.09.23模拟总结(T2)


    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 }
    View Code
  • 相关阅读:
    我孤独吗?我软弱吗?
    DataGrid 中的 HyperLinkColumn 如何传递多个参数?(未整理)
    C# 获取 MAC地址!
    (文本)文件操作
    ioninfinitescroll实现上拉分页加载更多
    前端面试题:防抖的实现
    vue 传送门功能,实现模态窗口
    前端面试题:节流的实现( 减少一段时间的触发频率)
    vue中的render函数
    ionic5实现tab栏切换效果
  • 原文地址:https://www.cnblogs.com/mrclr/p/9743790.html
Copyright © 2020-2023  润新知