题目链接
Description
李淳罡正在和别人战斗,他一共有 NN 把宝剑,选择每把宝剑都要付出一定的代价。为了能够顺利的战胜敌人,在连续 MM 把宝剑中至少要有一把宝剑要被选择。请计算总共最少花费多少代价,李淳罡才能顺利的战胜敌人
Input
第一行一个整数 TT (T≤10)(T≤10) ,表示测试数据组数,对于每组测试 :
第二行:两个整数 NN (1≤N≤2⋅106)(1≤N≤2⋅106), MM (1≤M≤N)(1≤M≤N)。其中 NN 表示宝剑的个数, MM 表示在连续 MM 把宝剑中至少要有一把要被选择。
接下来 N行,每行一个数 WiWi (1≤Wi≤105)(1≤Wi≤105),表示选择第 ii把宝剑所需的代价。
Output
对于每组测试数据,输出一行,表示答案。
1 5 3 1 2 5 6 2
4
题解:中文题,题意不说了。
题解:要是直接写普通DP,复杂度是O(n^2)。这样肯定过不了,现在直接用优先队列来维护最小值,这样复杂度能达到O(n)。
定义状态dp[i]表示,点燃第i个烽火台并保持第1~i个烽火台满足题意(每m个中至少一个被点燃),的最小花费是多少;状态转移方程:dp[i]=mindp[j](i-m=<j<=i-1)+w[i];
#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
//#include<unordered_map>
//#include<unordered_set>
const int maxn=2e6+10;
const int mod=1e9+7;
const int inf=1e9;
#define me(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&(-x)
#define mid l+(r-l)/2
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define PI 3.14159265358979323846
int dir[4][2]= {0,-1,-1,0,0,1,1,0};
int dx[]= {-2,-2,-1,-1,1,1,2,2};
int dy[]= {-1,1,-2,2,-2,2,-1,1};
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int a[maxn],que[maxn];
ll dp[maxn];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
int head=1,tail=0;
me(dp,0);
for(int i=1; i<=n; i++)
{
while(head<=tail&&dp[que[tail]]>=dp[i-1])///因为当前i还没有值,只能比较dp[i-1]的值。
tail--;
que[++tail]=i-1;
while(head<=tail&&que[head]<i-m)
head++;
dp[i]=a[i]+dp[que[head]];
}
ll ans=dp[n];
for(int i=n-m+1; i<=n; i++)
ans=min(ans,dp[i]);
printf("%lld\n",ans);
}
return 0;
}