[福建师大附中OJ 1264]烽火台

题目描述

  烽火台又称烽燧,是重要的防御设施,一般建在险要处或交通要道上。一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息:夜晚燃烧干柴,以火光传递军情。在某两座城市之间有n个烽火台,每个烽火台发出信号都有一定的代价。为了使情报准确的传递,在m个烽火台中至少要有一个发出信号。现输入n、m和每个烽火台发出的信号的代价,请计算总共最少需要话费多少代价,才能使敌军来袭之时,情报能在这两座城市之间准确的传递。

输入

输入的第一行有两个整数,分别为n和m。第二行有n个整数,分别表示每个烽火台发出信息的代价。

输出

输出仅有一行,为所求的最小代价。

样例输入

5 3
1 2 5 6 2

样例输出

4

提示

0<=n<=500000

0<=m<=n

数据保证运算在longint范围内

题解:
填坑中….
动态规划。
f[i]表示为 [1,i] [ 1 , i ] 的区间中,最后取的烽火台是第i个的最小花费。
f[0]=0 f [ 0 ] = 0
f[i]=min(f[i],f[j])+a[i] f [ i ] = m i n ( f [ i ] , f [ j ] ) + a [ i ]
(j[max(0,im),i)) ( j ∈ [ m a x ( 0 , i − m ) , i ) )
然后显然答案是 min(f[i]) m i n ( f [ i ] )
(i[nm+1,n]) ( i ∈ [ n − m + 1 , n ] )
然后因为n很大,转移过程又只需要找区间最小值就行,那么只需要一个线段树维护一下就OK了

#include
#include
#include
#include
#include
#include
#define LiangJiaJun main
#define INF 1999122700
using namespace std;
int n,m,a[500004];
int tr[2000004],up=1;
int query(int l,int r){
    int ans=INF;
    for(l=l+up-1,r=r+up+1;r-l>1;r>>=1,l>>=1){
        if(~l&1)ans=min(ans,tr[l+1]);
        if(r&1)ans=min(ans,tr[r-1]);
    }
    return ans;
}
void modify(int x,int pos){
     pos += up;
     tr[pos]=x;
     pos>>=1;
     while(pos){
         tr[pos]=min(tr[pos<<1],tr[pos<<1|1]);
         pos>>=1;
     }
     return ;
}
int LiangJiaJun (){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    while(up2)up<<=1;
    for(int i=1+up;i<=n+up;i++)tr[i]=INF;
    for(int i=up;i>=1;i--)tr[i]=min(tr[i<<1],tr[i<<1|1]);
    modify(0,1);
    for(int i=1+1;i<=n+1;i++){
        int lp=query(max(0+1,i-m),i-1)+a[i];
        modify(lp,i);
    }
    printf("%d\n",query(n-m+1+1,n+1));
    return 0;
}

你可能感兴趣的:(线段树)