ZOJ 2091 Mean of Subsequence

本文介绍了一种寻找具有最小平均值子序列的算法实现过程,通过动态规划的方法找到每个起始位置对应的最优结束位置,最终得出整个序列的最小平均值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

设i开头的子序列中,产生最小平均值的序列结尾下标为x[i]。

那么考虑x[i]确定之后的情况。a[i-1]如果比(i,x[i])的平均值小,那么x[i-1] = i-1。反之如果大于(i,x[i]),那么显然应把x[i]赋值于x[i-1]。

但是仍然有问题。考虑10,2,3,2的情况。设下标为1-4。x[4] = 4,x[3]=4,x[2]=2,x[1]=2。但是实际情况中,x[1]=4。为何?因为除了(2,2)能降低1的平均值外,(3,4)也能降低1开头序列的平均值。而且很容易得到如(2,2)(3,4)这样的一个阶梯型上升队列(j,x[j]),只要比较a[i-1]和(j,x[j])的平均值就可以判断是否需要继续迭代。

 

#include <cstdio>
#include 
<string>

int N, a[10001], sum[10001], x[10001];
double d[10001];

void init ();
void dp ();
void print ();
void pt ();

int main ()
{
    freopen ( 
"in.txt""r", stdin );
    
while ( scanf ( "%d"&N ) == 1 )
    
{
        
int i;
        
for ( i = 1; i <= N; i ++ )
            scanf ( 
"%d"&a[i] );
        init ();
        dp ();
        pt ();
        print ();
    }

    
return 0;
}


void init ()
{
    
int i, t = 0;
    sum[
0= t;
    
for ( i = 1; i <= N; i ++ )
    
{
        t 
+= a[i];
        sum[i] 
= t;
    }

}


void dp ()
{
    
int i, j, k;
    x[N] 
= N, d[N] = double ( a[N] );
    
for ( i = N - 1; i >= 1; i -- )
    
{
        
double dmin = double ( a[i] );
        x[i] 
= i, j = i + 1, k = x[j];
        
while ( j <= N )
        
{
            
double t = double ( sum[k] ) - double ( sum[j - 1] );
            t 
/= k - j + 1;
            
if ( t > a[i] )
                
break;
            
else
            
{
                t 
= double ( sum[k] ) - double ( sum[i - 1] );
                t 
/= k - i + 1;
                
if ( t < dmin )
                    x[i] 
= k, dmin = t;
                j 
= k + 1, k = x[j];
            }

        }

        d[i] 
= dmin;
    }

}


void print ()
{
    
double ave = 1e-10;
    
int i;
    
for ( i = 1; i <= N; i ++ )
        
if ( d[i] > ave )
            ave 
= d[i];    
    printf ( 
"%.6f ", ave );
}


void pt ()
{
    
int i, j;
    i 
= 1, j = x[i];
    
while ( i <= N )
    
{
        printf ( 
"%.6f ", d[i] );
        i 
= j + 1, j = x[i];
    }

    printf ( 
" " );
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值