hdu 3571 Hotaru's problem || 2015 Multi-University Training Contest 7 (manacher算法)

hud 5371 Hotaru’s probluem請戳

  1. 題意:
    給一個個數爲 n 數組 a,求連續且能分成等長的三段的最長的長度,三段關係:第一段和第二段對應元素滿足迴文,第一段和第三段對應元素相等相等,也就是說第二段和第三段也滿足迴文。

  2. 思路:
    這個自然想到用求迴文串的manacher算法解。manacher步驟參考最長迴文 made by xingyeyongheng
    依樣畫葫蘆,記 dp[i] 爲每個以下標 i 的迴文串的半徑,然後依次遍歷插入的元素的半徑,更新: ans = i - j ( j - i > ans && j < i + dp[i])
    答案就是:ans / 2 * 3(注:ans 初始值賦爲-1, 計算時數組a是擴展了的)
    開始小傻子我還是傻傻得想用另外一種算法做,感覺應該可以,無奈超時嚴重,後來用manacher加上遍歷,就過了,本來wwdd還肯定我這個會超時,想不到過了,想來是我這個樸素的方法還是可行的, 也比較容易理解。

  3. 複雜度:
    時間複雜度:O(n^2)
    空間複雜度:O(n)

  4. ac代碼

/* ***********************************************
Author        :Ilovezilian
Created Time  :2015/8/11 22:59:46
File Name     :1003_2.cpp
************************************************ */

#include <bits/stdc++.h>
#define fi(i,n1,n) for(int i = n1; i <= n; i ++)
#define fd(i,n1,n2) for(int i = n1; i >= n2; i --)
#define INF 0x7fffffff
#define ll long long
using namespace std;
const int N = 100010, mod = 1e9+7;

int a[N<<1], dp[N<<1];

int main()
{
    //freopen("","r",stdin);
    //freopen("","w",stdout);
    int cas, n, ans;
    scanf("%d", &cas);
    fi(ccas, 1, cas)
    {
        memset(a, -1, sizeof(a));
        memset(dp, 0, sizeof(dp));

        scanf("%d", &n);
        fi(i,1,n) scanf("%d", a + i*2);

        int len = n * 2, id = 0;
        a[0] = -2, a[len+2] = -3;
        dp[0] = dp[1] = dp[len+1] = 1;

        fi(i, 2, len + 1)
        {
            if(dp[id] + id > i) dp[i] = min(dp[id*2-i], dp[id] + id - i);
            else dp[i] = 1;

            while(a[i+dp[i]] == a[i-dp[i]]) dp[i] ++;//i + dp[i] <= len + 1 && i - dp[i] >= 1 && 
            if(dp[id] + id < i + dp[i]) id = i;
        }

        ans = -1;
        //fi(i,1,n) dp[i] = dp[i*2]/2;
        for(int i = 1; i <= len+1; i += 2) if(dp[i] + i <= len + 1)
        {
            for(int k = ans + 2; k <= dp[i]; k += 2)
            //if(dp[i] <= dp[i+k-1] || dp[i+k-1] >= dp[i])
            if(dp[i] >= k && dp[i + k - 1] >= k)
                ans = k;
        }

        //fi(i,1,len+1) printf("dp[%d] = %d\n", i, dp[i]);
        if(ans == 1) ans = 0;
        printf("Case #%d: %d\n",ccas, ans / 2 * 3);
    }

    return 0;
}
  1. 超時代碼
/* ***********************************************
Author        :Ilovezilian
Created Time  :2015/8/11 16:42:25
File Name     :1003_1.cpp
 ************************************************ */

#include <bits/stdc++.h>
#define fi(i,n1,n) for(int i = n1; i <= n; i ++)
#define fd(i,n1,n2) for(int i = n1; i >= n2; i --)
#define INF 0x7fffffff
#define ll long long
using namespace std;
const int N = 100010, mod = 1e9+7;

int a[N], n, ans;

int main()
{
    //freopen("","r",stdin);
    //freopen("","w",stdout);
    int cas, zz = 1;
    scanf("%d", &cas);
    while(cas--)
    {
        scanf("%d", &n);
        fi(i,1,n) scanf("%d", a + i);
        ans = 0;
        fi(i,1,n-1)
        {
            if(i + ans * 2 > n) break;

            if(a[i] == a[i+1])
            {
                int lr = min(i*3, n);
                for(int j = i + ans*2 + 2; j <= lr; j += 2) if(a[j] == a[i])
                { 
                    int len = (j - i) / 2;
                    ///printf("j = %d len = %d\n", j, len);
                    bool ok = 1;
                    for(int k = 1; k < len; k ++) if(a[i-k] != a[i+k+1] || a[i-k] != a[j-k])
                    {
                    //    printf("a[%d] = %d a[%d] = %d a[%d] =  %d\n", i-k, a[i-k], i + k + 1, a[i+k+1], j - k, a[j-k]);

                        ok = 0;
                        break;
                    }
                    if(ok) ans = len;
                }
            }
        }
        printf("Case #%d: %d\n", zz ++, ans * 3);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章