标签:
分类:dp | 线段树
题意转化:用m个区间去覆盖1~n,求所需区间的最小数目。
分析:假设输入的n个数中第i个数是应该输出的最大值,则通过所选若干区间的操作后,若能将其从第i个位置移动到第n个,则Maximizer正常工作。由分析可知,如果i = 1时maxmizer可以正常工作,则对于任意地i都可以正常工作。所以,不妨假设输入的第一个数是应该输出的最大值,然后利用DP求解。
dp[i]:= 将最大值从位置1移动到位置i时所需的最小区间数。
初始化:
dp[1] = 0(不需要移动时所需区间数为0)
dp[i] = INF(i > 1)
状态更新:
dp[ti] = min(dp[ti], dp[j] + 1)且si<=j <= ti
最坏时间复杂度:O(mn)
核心代码实现:
void solve(int n, int m)//n个数 m个区间
{
fill(dp, dp + n + 1, INF);
dp[1] = 0;
for(int i = 0; i <= m; ++i)
{
for(int j = s[i]; j <= t[i]; ++j)
dp[t[i]] = min(dp[t[i]], dp[j] + 1);
}
cout << dp[n] << endl;
}
本题可以利用线段树进行优化:查找区间(s[i], t[i])的最小值query(s[i], t[i])
优化后的代码实现:
void solve(int n, int m)
{//时间复杂度O(mlogn)
fill(dp, dp + n + 1, INF);
dp[1] = 0;
build_sbt(n);//构造线段树
update(1, 0);//将位置1置0
for(int i = 0; i < m; ++i)
{
int v = min(dp[t[i]], query(s[i], t[i]));
dp[t[i]] = v;
update(t[i], v);
}
cout << dp[t[i]] << endl;
}
标签:
原文地址:http://www.cnblogs.com/aizi/p/4662584.html