• [Luogu2600]合并神犇(dp,贪心)


    [Luogu2600]合并神犇

    题目背景

    loidc来到了NOI的赛场上,他在那里看到了好多神犇。

    题目描述

    神犇们现在正排成一排在刷题。每个神犇都有一个能力值p[i]。loidc认为坐在附近的金牌爷能力参差不齐非常难受。于是loidc便想方设法对神犇们进行人道主义合并。

    loidc想把神犇的能力值排列成从左到右单调不减。他每次可以选择一个神犇,把他合并到两侧相邻的神犇上。合并后的新神犇能力值是以前两位犇的能力值之和。每次合并完成后,被合并的两个神犇就会消失。合并后的新神犇不能再分开(万一他俩有女朋友咋办)因此每次合并后神犇的总数会减1.

    loidc想知道,想治好他的强迫症需要合并多少次

    输入输出格式

    输入格式:

    第一行一个整数 n。

    第二行 n 个整数,第 i 个整数表示 p[i]。

    输出格式:

    loidc需要合并的次数

    输入输出样例

    输入样例#1:

    8
    1 9 9 4 1 2 2 9

    输出样例#1:

    3

    说明

    对于 50%的数据,0< n <=5000。

    对于 100%的数据,0< n <=200000,0< p[i] <=2147483647,p 均为随机生成。

    乍一眼看题很容易错想成贪心,将序列一直合并到当前满足条件。
    但是我们考虑这样一组数据4 1 3 2 6.....
    如果按照我们贪心的思想,合并后的序列会变成4 4 8
    但实际上我们考虑序列4 6 6 同样可以从原序列用一样的步骤合并来,而6<8,显然对于后面序列的影响更小。
    所以这个贪心是错误的。
    想到dp,用(dp[i])表示合并到(i)需用的最小次数,因为从前面的状态状态转移过来,而数据不满足我们用(O(n^2))做,由前面的错误贪心我们可以得知,我们要合并到比下一个数小,这样我们对后面的影响就更小,所以我们直接找到第一个可以更新当前状态的决策来更新即可。
    最坏的时间复杂度到了(O(n^2)),但是数据比较水(手动滑稽),于是就顺利的A了
    记得long long

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define lll long long
    lll read()
    {
    	int x=0,w=1;char ch=getchar();
    	while(ch<'0'||ch>'9') {if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return x*w;
    }
    lll a[200010],dp[200010],f[200010],sum[200010];
    int main()
    {
    	lll n=read();
    	for(lll i=1;i<=n;i++)
    	{
    		a[i]=read();
    		sum[i]=sum[i-1]+a[i];
    	}
    	for(lll i=1;i<=n;i++)
    	{
    		lll j;
    		for(j=i-1;j>=0;j--)
    		if(sum[i]-sum[j]>=f[j]) break;
    		dp[i]=dp[j]+i-j-1;
    		f[i]=sum[i]-sum[j];
    	}
    	cout<<dp[n];
    }
    
  • 相关阅读:
    构建之法第九、十章读后感
    构建之法第七章读后感
    构建之法五、六章读后感
    构建之法第四章读后感
    一组阶段小记之再读构建之法
    打印控件
    TTS语音
    VS2005通过网络连接CE设备进行调试开发
    Windows XP下安装WinCE6.0开发环境
    利用VS2005创建WINCE 6.0 平台
  • 原文地址:https://www.cnblogs.com/lsgjcya/p/9143458.html
Copyright © 2020-2023  润新知