@topcoder - SRM603D1L3 @ SumOfArrays


desription @ @

列A、Bの所与2つの長さnの数 これで、C [I] = A [I] + B [i]は、次いで、二つの列重みに配置された対応する項目を追加することによって得ることができます。

会衆内Cの数の出現のあなたの最大数を構成することができる尋ねるだけでなく、この時点でのモード。公共の最大数を取るの様々なプログラムがある場合。

元のタイトルポータル。

@解決@

\(CNTA [i]が\)を表し\(I \) A、における発生数が\(CNTB [I] \)を表し\(I \) B.の出現回数を Cにおけるpの出現の最大数\(\ sum_ I = {0}} ^ {P \分(CNTA [I]、CNTB [PI])\)

それは特別なコンボリューションのように見えることに注意してください。我々は覚えて\(Fa_i(X)= \ sum_ P = {0}} ^ {MAX [CNTA [P] = I] {X ^ P} \)、共感メモを\(Fb_i(X)= \ sum_ {P ^ MAX {0} =} [CNTB [P] = I] X ^ P \に)答え:
\ [G(X)= \ sum_ {I = 1} ^ {N-} I \タイムズ(Fa_i(X)(\ sum_ {J = I + 1} ^ {N-} Fb_j(X))+ Fb_i (X)(\ sum_ {J = I + 1} ^ {n}はFa_j(X))+ Fa_i(X)Fb_i(X))\]

しかし、これは、高速暴力としてカウントされません。

注目\(\ CNTA SUM [i]は= N- \)私が会うCNTA [P]に、大きい= Pのiが小さくなる場合、つまり。
具体的には、A CNTA [P]で≥K HAVE \(O(\ FRAC {N } {K})\) 、BもA \(O(\ FRAC {N } {K})\) 。その後、我々はすべての可能な激しいタプル計算を列挙することができ、時間複雑である\(O(\ FRAC ^ {N-2} 2 ^ {K})\)
Kが大きい場合には、上記畳み込み方法に対して、この暴力アルゴリズムは、実際には、非常に高速です。

複雑そうと平衡時間を愛した:i <Kは、畳み込み演算の複雑さがあるため、\(O(K \ MAXタイムズ\タイムズ\ログMAX)\) ; iに対する> = K、列挙暴力複雑である\(O(\ FRAC {N
^ 2}、{K ^ 2})\) 以降、nおよびMAX同じ順序、我々は直接の原因\(Knを\ログN = \ FRAC {N ^ 2} {K ^ 2} \)、溶液であった(K =(\ {N-FRAC} {\ nログ})^ {\ FRAC。1 {{}}} \ 3 \)

次いで、総時間の複雑\(O(N ^ {\ FRAC。4} {} {}。3 \タイムズ\ ^ {ログ\ FRAC。3} {2} {} N-)\) 非常に悪いが、実際には非常に優れた見ながらA。

@acceptedコード@

#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

const int MOD = 998244353;
const int MAXN = (1 << 17);
const int K = 18;
const int G = 3;

inline int add(int x, int y) {return (x + y >= MOD ? x + y - MOD : x + y);}
inline int sub(int x, int y) {return (x - y < 0 ? x - y + MOD : x - y);}
inline int mul(int x, int y) {return 1LL * x * y % MOD;}

int pow_mod(int b, int p) {
    int ret = 1;
    for(int i=p;i;i>>=1,b=mul(b,b))
        if( i & 1 ) ret = mul(ret, b);
    return ret;
}

int w[22], iw[22];
void init() {
    for(int i=0;i<22;i++) {
        w[i] = pow_mod(G, (MOD - 1) / (1 << i));
        iw[i] = pow_mod(w[i], MOD - 2);
    }
}
int length(int n) {
    int len; for(len = 1; len < n; len <<= 1);
    return len;
}
void ntt(int *A, int n, int type) {
    for(int i=0,j=0;i<n;i++) {
        if( i < j ) swap(A[i], A[j]);
        for(int k=(n>>1);(j^=k)<k;k>>=1);
    }
    for(int i=1;(1<<i)<=n;i++) {
        int s = (1 << i), t = (s >> 1);
        int u = (type == 1 ? w[i] : iw[i]);
        for(int j=0;j<n;j+=s) {
            for(int k=0,p=1;k<t;k++,p=mul(p,u)) {
                int x = A[j+k], y = mul(p, A[j+k+t]);
                A[j+k] = add(x, y), A[j+k+t] = sub(x, y);
            }
        }
    }
    if( type == -1 ) {
        int iv = pow_mod(n, MOD - 2);
        for(int i=0;i<n;i++)
            A[i] = mul(A[i], iv);
    }
}

class SumOfArrays{
    public:
        vector<pair<int, int> >na, nb;
        int f[2*MAXN + 5];
        int ca[MAXN + 5], cb[MAXN + 5];
        int a[MAXN + 5], b[MAXN + 5];
        int ta1[2*MAXN + 5], ta2[2*MAXN + 5], tb1[2*MAXN + 5], tb2[2*MAXN + 5], tmp[2*MAXN + 5];
        string findbestpair(int n, vector<int>A, vector<int>B) {
            init();
            a[0] = A[0], a[1] = A[1], b[0] = B[0], b[1] = B[1];
            for(int i=2;i<n;i++) {
                a[i] = (1LL*A[2]*a[i-1]%A[5] + 1LL*A[3]*a[i-2]%A[5] + A[4]) % A[5];
                b[i] = (1LL*B[2]*b[i-1]%B[5] + 1LL*B[3]*b[i-2]%B[5] + B[4]) % B[5];
            }
            for(int i=0;i<n;i++)
                ca[a[i]]++, cb[b[i]]++;
            for(int i=0;i<MAXN;i++) {
                if( ca[i] >= K ) na.push_back(make_pair(i, ca[i]));
                if( cb[i] >= K ) nb.push_back(make_pair(i, cb[i]));
            }
            for(int i=0;i<(int)na.size();i++)
                for(int j=0;j<(int)nb.size();j++)
                    f[na[i].first + nb[j].first] += min(na[i].second, nb[j].second);
            for(int i=1;i<K;i++) {
                bool flag = false;
                for(int j=0;j<MAXN;j++) {
                    if( ca[j] > i ) ta1[j]++;
                    else if( ca[j] == i ) ta2[j]++, flag = true;
                    
                    if( cb[j] > i ) tb1[j]++;
                    else if( cb[j] == i ) tb2[j]++, flag = true;
                }
                int len = 2*MAXN;
                if( flag ) {
                    ntt(ta1, len, 1), ntt(ta2, len, 1), ntt(tb1, len, 1), ntt(tb2, len, 1);
                    for(int j=0;j<len;j++)
                        tmp[j] = add(add(mul(ta1[j], tb2[j]), mul(ta2[j], tb1[j])), mul(ta2[j], tb2[j]));
                    ntt(tmp, len, -1);
                    for(int j=0;j<len;j++)
                        f[j] = add(f[j], mul(tmp[j], i));
                }
                for(int j=0;j<len;j++) ta1[j] = ta2[j] = tb1[j] = tb2[j] = tmp[j] = 0;
            }
            
            int ans = 0, res;
            for(int i=2*MAXN-1;i>=0;i--)
                if( f[i] > ans ) ans = f[i], res = i;
            string ret = "";
            while( res ) ret = (char)(res % 10 + '0') + ret, res /= 10;
            ret = " " + ret;
            while( ans ) ret = (char)(ans % 10 + '0') + ret, ans /= 10;
            return ret;
        }
};

詳細@

なぜ関数は、人類に対して、そのような犯罪へのフォームの値を返すだけでなく、数値文字列に変換しなければなりません。直接のリターンは、配列は非常に良いではありません。

おすすめ

転載: www.cnblogs.com/Tiw-Air-OAO/p/12466134.html