この問題に対する低コストのソリューションを購入[P1108]

トピックリンク

購入する安価なソリューション

タイトル効果:最長シーケンスの長さが減少の列数を求め、そして最長のシーケンスの数を減らします

タイトル分析:直接普通使用することができ、最長のドロップシーケンスがルーチン操作で見つける\(O(N ^ 2) \) アルゴリズム、またバイナリ達成するために使用することができる\(O(nlogn)\)の複雑さを、しかし(\ n個の\当量5000 \)だけを実行単純なアルゴリズム

それでは、どのよう統計は、それをプログラム?

我々は(DP \)\最長シーケンスがドロップ提供さ見つける\(D(I)\)で表さ\(私は\)エンド・ドロップ・シーケンスの最大長。同様に、私たちが使用することができます\(F(I )\)で表される\(Iは\)終了、長さ\(D(I)\)液滴のサブシーケンスの数

不难想到\(F(I)= \ {}ケース1 \ qquadのD(I)== 1 \\はsum_ {J} ^ {I - 1} \開始\ \ {F(j)は、| \; J <I \; \; \&\&\; \; F(J)+ 1 ==のF(I)\} \端{ケース} \)

しかし、そうするための、問題があるダブルカウント

もしそこに\(D(I)== D (J)\) と\(A(I)A ==(J)\) および満たすI $ <J \(、持っている\) F(I)\のLeq F(J)$

その理由は、単純です\(F(i)が\)全てのプログラムがあるの\(F(J)\)含まれており、その後、あなたがする必要があります(\)は、f(j)を\に設定されている\(0 \)、または\(\ F(J))プログラムが複数回カウントされます

コード提供、小規模な書き込み上のデータ\(O(N ^ 2) \) アルゴリズム

#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 8192;
int val[maxn],g[maxn],d[maxn],f[maxn],n,ans;//val为原数列,d[i]表示以i结尾的最长下降子序列长度,f[i]表示以i结尾,长度为d[i]的下降子序列的数量
int main(){
    ios::sync_with_stdio(false);
    cin >> n;
    for(int i = 1;i <= n;i++)
        cin >> val[i];
    for(int i = 1;i <= n;i++)
        g[i] = -0x7fffffff;
    ans = -1;
    for(int i = 1;i <= n;i++){
        int k = 0;
        int l = 1,r = n;
        while(l <= r){
            int mid = (l + r) >> 1;
            if(g[mid] > val[i])k = mid,l = mid + 1;
            else r = mid - 1;
        }
        d[i] = k + 1;
        g[k + 1] = val[i];
        ans = max(ans,d[i]);
    }
    cout << ans << " ";//求LIS,没啥好说的
    for(int i = 1;i <= n;i++){//依照转移方程
        if(d[i] == 1)f[i] = 1;
        for(int j = 1;j < i;j++)
            if(d[i] == d[j] && val[i] == val[j])//如果j的方案已经被i包含了
                f[j] = 0;
            else if(d[i] == d[j] + 1 && val[i] < val[j])//统计方案
                f[i] += f[j];
    }
    int sum = 0;
    for(int i = 1;i <= n;i++){//输出答案
        if(d[i] == ans)sum += f[i];
    }
    cout << sum << '\n';
    return 0;
}

おすすめ

転載: www.cnblogs.com/colazcy/p/11514975.html