RT,思路如下,错第5,6,7点
/*luogu P1281
思路:
先不考虑如何求出第几个人看的书的编号,而是求出总时间的最小值
设f[i][j]为第i个人,总共选到第j本书的时间最短值
既然每个人至少选一本书,那么第i个人至少从第i本书选起
j从i开始枚举,一直枚举到m
在这之间,对于每一个j,i到j之间任何一个点都可以分割开来
那么f[i][j] = min(max(f[i - 1][j - k]) , sum(a[j - k + 1]~a[j]))
第二阶段:状态的记录
设置一个pair数组,在每次利用最小值更新某一状态后,就记录下转移前的状态
因为每个状态只进行一次循环,在循环后记录的一定是对于这个状态的最优解
所以无后效性
*/
#include <bits/stdc++.h>
using namespace std;
struct node{
pair<int , int > st = make_pair(0, 0);//当前状态
pair<int , int > pre_st = make_pair(0, 0);//从哪个状态转移
};
int m, tp;//m books and tot_person persons
int book[505];
int f[505][505];
int sum[505];
node sta[505][505];//记录状态f[i][j]是从哪一个状态转移过来
void __INIT()
{
ios::sync_with_stdio(false);
memset(f, 0x3f3f3f3f, sizeof(f));
cin>>m>>tp;
for(int i = 1;i <= m;++ i)
cin>>book[i];
for(int i = 1;i <= m;++ i)
sum[i] = sum[i - 1] + book[i];//记录前缀和,用于算部分和(状态转移方程的后半部分)
return ;
}
void dfs(int x, int y)
{
if(x == 0 || y == 0) return ;
if(x == 1)
{
cout<<sta[x][y].st.first<<' '<<sta[x][y].st.second<<endl;
return ;
}
else
{
dfs(sta[x][y].pre_st.first, sta[x][y].pre_st.second);
cout<<sta[x][y].st.first<<' '<<sta[x][y].st.second<<endl;
return;
}
return ;
}
int main()
{
__INIT();
for(int i = 1;i <= m;++ i)
f[1][i] = sum[i];
for(int i = 1;i <= m;++ i)
{
pair<int , int > ins = make_pair(1, i);
sta[1][i].st = ins;
}
for(int i = 1;i <= m;++ i)
{
for(int j = i;j <= m;++ j)
{
int tmp;
for(int k = j;k >= 1;-- k)
{
tmp = max(f[i - 1][j - k], sum[j] - sum[j - k]);
if(f[i][j] > tmp)
{
f[i][j] = tmp;
sta[i][j].st = make_pair(j - k + 1, j);
sta[i][j].pre_st = make_pair(i - 1, j - k);
}
}
}
}
// cout<<f[tp][m]<<endl;
dfs(tp, m);
return 0;
}