• 【NOIP2012模拟11.1】塔(加强)


    题目

    玩完骰子游戏之后,你已经不满足于骰子游戏了,你要玩更高级的游戏。
    今天你瞄准了下述的好玩的游戏:
    首先是主角:塔。你有N座塔一列排开。每座塔各自有高度,有可能相等。
    这个游戏就不需要地图了。
    你每次可以选择相邻的两座塔合并在一起,即这两座塔的高度叠加后变成了同一座塔。然后原本分别与这两座塔相邻的塔变得与这座新的塔相邻。
    你的目标是在使用最少的操作次数在游戏的最后获得一列塔,这些塔的高度从左到右形成一个不下降的数列。

    分析

    这是到结论题。。。
    结论一:每个块越小越好。
    so,设(f_i)表示处理完了i的最小操作次数。再设(h_i)表示最优情况下的(g_i)的i所在的塔的高度最小值。
    转移为:

    [f_i=min(f_i,f_j+i-j-1(g_j<=sum(j+1...i))) ]

    这是(O(n^2))的。
    我们想办法优化它,
    首先,因为(f_i+1>=f_{i+1})
    结论二,当我们枚举j从后往前搜,当高度合法,就是最优的答案,也就可以break。
    但是,这还是超时了。
    我们打个单调队列。

    #include <cmath>
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    const long long maxlongint=2147483647;
    const long long mo=1000000007;
    const long long N=1000025;
    using namespace std;
    long long f[N],a[N],n,maxa,ans=maxlongint,sum[N],g[N],d[N];
    int main()
    {
    	memset(f,0,sizeof(f));
    	memset(g,0,sizeof(g));
    	scanf("%lld",&n);
    	f[0]=g[0]=0;
    	long long l,r;
    	d[l=r=1]=0;
    	for(long long i=1;i<=n;i++) scanf("%lld",&a[i]),maxa=max(a[i],maxa),sum[i]=sum[i-1]+a[i];
    	for(long long i=1;i<=n;i++)
    	{
    			while(g[d[l+1]]+sum[d[l+1]]<=sum[i] && l<r) l++;
    			long long sigma=sum[i]-sum[d[l]];
    			f[i]=f[d[l]]+i-d[l]-1;
    			g[i]=sigma;
    			while(g[d[r]]+sum[d[r]]>=sum[i]+g[i] && l<=r) r--;
    			d[++r]=i;
    	}
    	printf("%lld",f[n]);
    }
    
  • 相关阅读:
    ES6学习之数组扩展
    js三元表达式
    ES6学习之函数扩展
    TS学习之for..of
    TS学习之Symbol
    Visual Studio编译时报错“函数名:重定义;不同的基类型”
    Windows Visual Studio中修改PostgreSQL代码后调试报错
    Windows安装MySQL5.7.17
    289. Game of Life -- In-place计算游戏的下一个状态
    Swift的 convenience && designated init
  • 原文地址:https://www.cnblogs.com/chen1352/p/9045305.html
Copyright © 2020-2023  润新知