ICPCノースセントラルNAコンテスト2017 D.スムーズアレイ - DP、剪枝

こちらです

質問の意味:

入力は、N kはS、N現在のシーケンスの長さを表し、sは任意であり、kを表す連続の個数であり、あなたは、動作は任意の数の数が位置0-Sとなるかもしれ有しますあなたはSを満たすために、少なくともいくつかの操作を行うことができるようにしたいです

ソリューション:

kの列に配列の長さのこの期間の後、各列は同じです。
そして、あなたは、このようなAの事にそれを回すことができます。
ここに画像を挿入説明
デジタルの各列と同じです。それは、我々を示唆し、データは5000の範囲であります n個 2 N ^ 2 DP [I] [j]は、i番目の位置を示し、次に、i番目の列の前部には、最小量の必要な位置転写及びJです。
電流が列挙どの位置、列挙DP [I-1]、その後転送に変換されるときに、最も単純なアイデアは、i番目の位置に、この転送はK ^ 3、メイク生活困難です。
その後、大規模なkが、その後、列の数が非常に小さい場合、実際には、kが小さいことを発見し、列の数が非常に充実しています。そうしてあなたは転送され、現在の列のいくつかの数を列挙することができます。心配事がないの数に、それはすべての場所+ I番目の列の数でなければなりません。したがって、この場合には、再び列挙です D P [ ] [ J ] 0 < = J < = S DP [I]、[J](0 <= jの<= S) から入手可能です、
D P [ - 1 ] [ K ] 0 < = K < = J DP [I-1] [K](0 <= K <= j)は を介して転送します。次いで、[I-1] MIを有するアレイの最小プレフィックスDPを維持します。
状態遷移方程式は、

dp[i][j]=min(dp[i][j],mi[j]+num[i]);
#include<bits/stdc++.h>
using namespace std;
const int N=5e3+5;
int dp[N][N],mi[N],num[N],siz[N][N];
vector<int>vec[N];
int a[N];
int main()
{
    int n,k,s;
    scanf("%d%d%d",&n,&k,&s);
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]),num[i%k]++;
        if(!siz[i%k][a[i]])
            vec[i%k].push_back(a[i]);
        siz[i%k][a[i]]++;
    }
    for(int i=0;i<=k;i++)
        for(int j=0;j<=s;j++)
            dp[i][j]=1e9;
    //memset(mi,125,sizeof(mi));
    for(int i=0;i<=s;i++){
        dp[0][i]=num[0]-siz[0][i];
        mi[i]=i?min(mi[i-1],dp[0][i]):dp[0][i];
    }
    for(int i=1;i<k;i++){
        for(auto j:vec[i]){
            for(int k=j;k<=s;k++)
                dp[i][k]=min(dp[i][k],dp[i-1][k-j]+num[i]-siz[i][j]);
        }
        for(int j=0;j<=s;j++)
            dp[i][j]=min(dp[i][j],mi[j]+num[i]);

        for(int j=0;j<=s;j++)
            mi[j]=j?min(mi[j-1],dp[i][j]):dp[i][j];
    }
    printf("%d\n",dp[k-1][s]);
    return 0;
}
/*
16 4 10
5 2 3 5 5 2 3 5 5 2 3 5 5 3 1 5
*/
公開された554元の記事 ウォン称賛31 ビュー50000 +

おすすめ

転載: blog.csdn.net/tianyizhicheng/article/details/104600786