乍看此题,还以为是扫描线+贪心,每次都扫描出最多的那个站,但是时间复杂度太高,而且写到一半的时候发现了反例. . . . .
接下来开始推式子:
dp[ i ][ j ] = max(dp[ k1 ][ j ],dp[ k2 ][ j -1] + ans[site[ k2 ][j-1]+1][i])。
k1 ∈[j,i],k2 ∈[j-1,i].
site[ i ][ j ]表示的dp[ i ][ j ]这种情况下最右边的洗脑设备的位置.
ans[ i ][ j ]表示 以 k ∈ [ i , j ] 为始发站,经过 j 且不以 j 为终点的客人数量.
好了,理清上面的思路后问题的难点就变成了 如何统计出 ans[ ][ ]。
如果单纯的暴力枚举时间复杂度是o(n^4),二维的线段树倒是可以胜任,但是我忘了怎么写了。。。
然后学姐说可以试一试能否转化成简单的矩阵DP。
设,Map[ i ][ j ]存储的为 i 到 j 的客流量,i >= j 时,Map[ i ][ j ] = 0。
则ans[ x ][ y ] = sigma Map[ i ][ j ] ( x <= i <= y ,y < j <= n)。
接下来可以用 2*n^2 的时间将Map[ i ][ j ]处理成 (1,1) 到 ( i , j )的矩形范围内元素的和。
则 ans[ i ][ j ] = Map[ j ][ n ] - Map[ j ][ j ] - Map[ i-1 ][ n ] + Map[ i-1 ][ j ]。
显然这种方法预处理的时间较高,但查询只需要o(1)。缺点在于不能更新。
对于打印路径只需要在dp的时候记录一下前驱即可,不再赘述。
就这个烂题竟然卡了两天。。。。
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <stack>
#pragma comment(linker, "/STACK:1024000000");
#define EPS (1e-8)
#define LL long long int
#define ULL unsigned long long int
#define _LL __int64
#define _INF 0x3f3f3f3f
#define INF 40000000
#define Mod 1000000009
using namespace std;
int Map[501][501];
struct N
{
int site,data,pn,pm;
}dp[501][501];
int ans[501][501];
bool path[510];
void dfs(int n,int m)
{
if(n == 0 || m == 0)
return ;
if(dp[n][m].pm != m)
path[n] = true;
dfs(dp[n][m].pn,dp[n][m].pm);
}
int main()
{
int n,m,i,j,k,t;
scanf("%d %d",&n,&m);
memset(Map,0,sizeof(Map));
for(i = 1;i < n; ++i)
{
for(j = i+1;j <= n; ++j)
{
scanf("%d",&Map[i][j]);
}
}
for(i = 1;i <= n; ++i)
{
for(j = 1;j <= n; ++j)
{
Map[i][j] += Map[i][j-1];
}
}
for(j = 1;j <= n; ++j)
{
for(i = 1;i <= n; ++i)
{
Map[i][j] += Map[i-1][j];
}
}
memset(ans,0,sizeof(ans));
for(i = 1;i <= n; ++i)
{
for(j = 1;j <= n; ++j)
{
ans[i][j] = Map[j][n] - Map[j][j] - Map[i-1][n] + Map[i-1][j];
}
}
for(i = 0;i <= n; ++i)
{
dp[i][0].data = 0;
dp[i][0].site = 0;
}
for(i = 1;i <= n; ++i)
{
for(t = min(i,m),j = 1;j <= t; ++j)
{
dp[i][j].data = dp[j-1][j-1].data + ans[dp[j-1][j-1].site+1][i];
dp[i][j].site = i;
dp[i][j].pn = j-1;
dp[i][j].pm = j-1;
for(k = j;k <= i; ++k)
{
if(dp[k][j].data > dp[k][j-1].data + ans[dp[k][j-1].site+1][i])
{
if(dp[k][j].data > dp[i][j].data)
{
dp[i][j] = dp[k][j];
dp[i][j].pn = k;
dp[i][j].pm = j;
}
}
else
{
if(dp[k][j-1].data + ans[dp[k][j-1].site+1][i] > dp[i][j].data)
{
dp[i][j].data = dp[k][j-1].data + ans[dp[k][j-1].site+1][i];
dp[i][j].site = i;
dp[i][j].pn = k;
dp[i][j].pm = j-1;
}
}
}
}
}
memset(path,false,sizeof(path));
dfs(n-1,m);
printf("%d\n",dp[n][m].data);
for(i = 1;i <= n;++i)
{
if(path[i])
{
printf("%d",i);
break;
}
}
for(++i;i <= n;++i)
{
if(path[i])
{
printf(" %d",i);
}
}
puts("");
return 0;
}