【BZOJ3152】组合子逻辑,贪心+堆

3152: [Ctsc2013]组合子逻辑

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 176 Solved: 107
[Submit][Status][Discuss]
Description

组合子逻辑是Moses Schönfinkel和Haskell Curry发明的一种符号系统,用于消除数理逻辑中对于变量的需要。本题考察一种与真实世界的组合子演算略有差别的组合子系统。 一个组合子项是下列形式之一:
P
(E1 E2)
其中P表示一个基本函数,E1以及E2表示一个组合子项(可以相同)。不满足以上形式的表达式均非组合子项。
我们将一个组合子项E的参数个数np(E)如下:
np(P) = 基本函数P的参数个数;
np((E1 E2)) = np(E1) - 1。
本题中,我们用一个正整数同时表示一个基本函数,以及该基本函数的参数个数。 对于一个组合子项E,如果它和它包含的所有组合子项的参数个数np均为正整数,那么我们称这个E为范式。
我们经常组合子项简化表示:如果一个组合子项E含有连续子序列(… ((E1 E2) E3) … En) (其中n ≥ 3),其中Ek表示组合子项(可以是简化表示的),那么将该部分替换为(E1 E2 E3 … En),其他部分不变,得到表达式E的一个简化表示。一个组合子项可以被简化表示多次。 给定一个基本函数序列,问至少需要添加多少对括号,才能使得该表达式成为一个范式的简化表示(即满足范式的性质);如果无论如何怎样添加括号,均不能得到范式的简化表示,输出-1。
Input

第一行包含一个正整数T,表示有T次询问。 接下来2T行。 第2k行有一个正整数nk,表示第k次询问的序列中基本函数的个数。 第2k + 1行有nk个正整数,其中第i个整数表示序列中第i个基本函数。

Output

输出T行,每行一个整数,表示对应询问的输出结果。
Sample Input

2

5

3 2 1 3 2

5

1 1 1 1 1

Sample Output

3

-1

HINT

【样例说明】

第一次询问:一个最优方案是(3 (2 1) (3 2))。可以证明不存在添加括号对数更少的方案。

第二次询问:容易证明不存在合法方案。

令TN表示输入中所有nk的和。TN≤2000000
写在前面:怎么感觉最近不在状态了?又到了退役的季节?

思路:读题读了半个小时才明白题意= =
主要是把原序列a逐渐缩点最终形成一个不上升序列,从头开始往下划拉(初值k为a[1]),如果到第i个点时k>1(即可以拓展)就k–,如果k=1那么一定要在已经拓展的点x中再拓展出一个子序列(且易知这个子序列一定能被k拓展),这样k=k+x-1(因为k可以不必一个个扩展这个子序列中的点,而是直接扩展整个子序列,消耗的价值由子序列的长度len减为1,而len就等于这个序列中最大的点,即最左边的点的权值-1,就是大于1的点可以帮助拓展),同时ans++。因此我们知道肯定先用之前读过的最大的点(max{a[2],a[3]…a[i-1]})来扩展肯定是最优的且能扩展的序列max长度一定是它的权值-1,所以加一个堆来存放之前读进来的a[i]就可以了,当(空堆||最大值为1)&&k<=1时,输出-1。
还有一点就是n=1时要注意,如果读入的数不用括号就可以(输出0)

#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std;
int t,n,a[2000010];
int in()
{
    int t=0;
    char ch=getchar();
    while (ch>'9'||ch<'0') ch=getchar();
    while (ch>='0'&&ch<='9') t=t*10+ch-'0',ch=getchar();
    return t;
}
void solve()
{
    int ans=1;
    n=in();
    if(n==1) {if (in())printf("0\n");else printf("-1\n");return;} 
    priority_queue <int> team;
    for (int i=1;i<=n;i++) a[i]=in();
    int k=a[1];
    for (int i=2;i<=n;i++)
    {
        while (k<=1) 
        if (team.empty()||team.top()==1){printf("-1\n");return;}
        else ans++,k+=team.top()-1,team.pop();
        k--;
        team.push(a[i]);
    }
    printf("%d\n",ans);
}
main()
{
    t=in();
    while (t--) solve();
}

你可能感兴趣的:(【BZOJ3152】组合子逻辑,贪心+堆)