题意:
现在有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; }