FZU - 2267(後綴數組)

點擊打開鏈接

Fat brother and Maze are playing a kind of special (hentai) game with two integers. All the digits of these two integers are in the range from 1 to 9. After they’ve got these two integers, they thought that these two numbers were not large enough! (You know that the young people always like the HUGE THING in order to have more pleasure) So they decide to use the digits of these two integers to make a new BIGGER integer. At the beginning of this game, the new integer has no digit, each time Fat Brother and Maze can choose one of the two initial integers (if this integer exists) and move its first digit to the end of the new integer. For instance, if the new integer is 233 and the two initial integers are 3154 and 1324 now, they can choose the first digit of the integer 3154, which is 3, and add it to the end of the new integer to make it become 2333. The two initial integers are 154 and 1324 now after this action. Also they can choose the first digit of the integer 1324 and add it to the end of the integer 233 and make it become 2331. This process goes until the two initial integers are all empty. Now Fat Brother and Maze would like to know the maximum number they could get after this special (hentai) game.

Input

The first line of the date is an integer T (1 <= T <= 102), which is the number of the text cases.

Then T cases follow, each case contains two integers N and M (1 <= N,M <= 100000) indicated the number of the digits of these two integers. Then a line with N digits indicates the first integer and a line with M digits indicates the second integer. Note that all the digits are in the range from 1 to 9.

In 90% of test cases, N, M <= 1000.

Output

For each case, output the case number first, and then output the integer Fat Brother and Maze would get, this integer should be as large as possible.

Sample Input
1
3 4
2 5 2
3 6 3 1
Sample Output
Case 1: 3632521
題意:給出兩個數組,要求在不改變兩個數組內部順序的前提下合併兩個數組,最後得到的數組的字典序最大。

思路:講道理一開始只知道O(n^2)的解法,後來看題解才知道是用後綴數組,複雜度降低賊多啊!!!後綴數組的話感覺還是比較難理解的,具體的學習可以參照:後綴數組

然後題目就變得很明顯了,具體的也是參照基神的模板寫的後綴數組模板,感覺基神的代碼真的很容易看懂,思路賊清晰的那種。。。


#include<stdio.h>
#include<iostream>
#include<set>
#include<queue>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
using namespace std;
const int inf = 0x3f3f3f3f ;

const int MX = 2e5 + 5;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int a[MX] , ans[MX];
char s[MX];
int SA[MX], R[MX], H[MX];
int wa[MX], wb[MX], wv[MX], wc[MX];
bool cmp(int *r, int a, int b, int l) {
    return r[a] == r[b] && r[a + l] == r[b + l];
}
void Suffix(int *r, int n ,int m = 128) {
    //int n = strlen(r) + 1;
    int i, j, p, *x = wa, *y = wb, *t;
    for(i = 0; i < m; i++) wc[i] = 0;
    for(i = 0; i < n; i++) wc[x[i] = r[i]]++;
    for(i = 1; i < m; i++) wc[i] += wc[i - 1];
    for(i = n - 1; i >= 0; i--) SA[--wc[x[i]]] = i;
    for(j = 1, p = 1; p < n; j *= 2, m = p) {
        for(p = 0, i = n - j; i < n; i++) y[p++] = i;
        for(i = 0; i < n; i++) if(SA[i] >= j) y[p++] = SA[i] - j;
        for(i = 0; i < n; i++) wv[i] = x[y[i]];
        for(i = 0; i < m; i++) wc[i] = 0;
        for(i = 0; i < n; i++) wc[wv[i]]++;
        for(i = 1; i < m; i++) wc[i] += wc[i - 1];
        for(i = n - 1; i >= 0; i--) SA[--wc[wv[i]]] = y[i];
        for(t = x, x = y, y = t, p = 1, x[SA[0]] = 0, i = 1; i < n; i++) {
            x[SA[i]] = cmp(y, SA[i - 1], SA[i], j) ? p - 1 : p++;
        }
    }
    int k = 0; n--;
    for(i = 0; i <= n; i++) R[SA[i]] = i;
    for(i = 0; i < n; i++) {
        if(k) k--;
        j = SA[R[i] - 1];
        while(r[i + k] == r[j + k]) k++;
        H[R[i]] = k;
    }
}//後綴數組的寫法
int main()
{
    int t , kk = 1;
    scanf("%d" , &t) ;
    while(t--){
        int n , m ;
        scanf("%d%d" , &n , &m) ;
        for(int i = 0 ; i < n ; i ++)
            scanf("%d" , &a[i]);
        a[n] = 0;
        for(int i = n + 1 ; i < m + n + 1 ; i ++)
            scanf("%d" , &a[i]);
        a[n+m+1] = 0 ;
        int len = n + m + 1;
        Suffix(a , n + m + 1);
        int p1 = 0 , p2 = n + 1 , k = 0;
        while(p1 < n && p2 < len){
            if(a[p1] > a[p2])
                ans[k++] = a[p1++] ;
            else if(a[p1] < a[p2])
                ans[k++] = a[p2++] ;
            else if(R[p1] > R[p2])//相等的話比較rank就行
                ans[k++] = a[p1++];
            else
                ans[k++] = a[p2++];
        }
        while(p1 < n)//最後如果還有多餘的,再放進來
            ans[k++] = a[p1++];
        while(p2 < len)
            ans[k++] = a[p2++];
            printf("Case %d: " , kk++);
        for(int i = 0 ; i < n + m ; i ++)
            cout<<ans[i];
        cout<<endl;
    }
    return 0;
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章