Gym

原题链接

题意

现在有n个人,s个位置和你可以划分长k个区域
你可以把s个位置划分成k个区域,这样每个人坐下你的代价是该区域内,在你之前比你小的人的数量
问你怎么划分这s个位置(当然,每个区域必须是连续的),才能使得总代价最小,输出代价。

分析
dp[i][j]表示第i个位置是第j个区域的结尾,dp[i][j]→dp[t][j+1]暴力转移。但是需要预处理每个范围里的代价值,需要树状数组维护。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1050;
int dp[maxn][55];
int sum[maxn][maxn];
int r[maxn];
int n,m,k;
int a[maxn];
vector<int> E[maxn];
int lowbit(int x)
{
    return x&(-x);
}
int get(int x)
{
    int ans = 0;
    for(int i=x;i;i-=lowbit(i))
        ans+=a[i];
    return ans;
}
void update(int x,int v)
{
    for(int i=x;i<maxn;i+=lowbit(i))
        a[i]+=v;
}
int main()
{
    freopen("flight.in","r",stdin);
    freopen("flight.out","w",stdout);
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&r[i]);
        E[r[i]-1].push_back(i);
    }
    for(int i=0;i<m;i++)
    {
        memset(a,0,sizeof(a));
        for(int j=i;j<m;j++)
        {
            if(i!=j)sum[i][j]=sum[i][j-1];
            for(int t=0;t<E[j].size();t++)
                sum[i][j]+=get(E[j][t]);
            for(int t=0;t<E[j].size();t++)
                update(E[j][t],1);
        }
    }

    for(int i=0;i<=m;i++)
        for(int j=0;j<=k;j++)
            dp[i][j]=1e9;
    dp[0][0]=0;
    for(int i=0;i<m;i++)
        for(int j=0;j<k;j++)
        {
            if(dp[i][j]==1e9)continue;
            for(int t=i;t<m;t++)
                dp[t+1][j+1]=min(dp[t+1][j+1],dp[i][j]+sum[i][t]);
        }
    cout<<dp[m][k]<<endl;
}
原文地址:https://www.cnblogs.com/fht-litost/p/7271439.html