• 【树状DP】星象仪


    题目描述

    在寂寞的夜里,星象仪是非常浪漫的东西。但是,你作为一个精神稍微有点不太正常的Geek,把原本正常的星象仪改造得像电报发送器一样。当然,你这个的构造还要更加奇葩一点。具体来说,你的星象仪是一棵满二叉树,二叉树的节点都是有两个输入端和一个输出端的AND 门或者OR 门。它们输入和输出的信号都是只是0 或者1。它们会接受子节点的输出信号,然后将这两个信号进行AND 运算或者OR 运算作为自己的输出。然后,根节点的输出信号就是整个星象仪的输出信号。叶节点的输入信号是由你来调整的,如果二叉树有K 层,那么你显然有2K 个输入信号可以调整。调整一次当然只能改变一个输入信号。根据你的设定,在一开始所有的输入端的输入信号都是0。现在你希望用星象仪得到一串信号,为此,你需要不停地调整输入。假定你想要用图中的星象仪得到输出信号000111,一种可行的方案是0001→0011→1100→1111→1010→0101,但是这样你要调整14 次输入信号。更加方便的方式是0000→

    0000→0000→0101→0101→0101,这样你总计只需要调整2次输入信号。在一开始所有的输入端的输入信号都是0。现在你希望用星象仪得到一串信号,为此,你需要不停地调整输入。由于调整输入信号是一件非常麻烦的事情,现在你希望知道对于一台给定的星象仪,如果想要得到一串给定的信号,至少需要调整多少次输入。


    输入格式

    输入文件包含多组测试数据。第一行有一个整数T,表示测试数据的组数。

    测试数据的第一行是一个正整数 N,表示输入信号的数目。保证N 是2 的整数次幂。

    第二行含有一个由 0 和1 组成的字符串S,表示你想要得到的信号。

    第三行包含 N – 1 个整数,按照层次遍历顺序给出满二叉树的每个节点。整数只会是0

    或者1。0 表示二叉树的这个位置是一个OR 门,1 表示是一个AND 门。

    输出格式

    对于每组测试数据,在单独的一行内输出结果。

    样例输入

    2

    4

    010101

    0 0 0

    4

    111111

    1 1 1

    样例输出

    5

    4

    数据范围与约定

    对于30% 的数据,N≤16,S 的长度在100 之内。

    对于 100% 的数据,T≤100,N≤8192,S 的长度在10000 之内。

    分析

    如果输入都是0,不用管,因为无论是与门还是或门出来都是0,所以找第一个1。

    对于1,如果它本身是与门,他的左右儿子一定都是1,如果是或门,左右儿子有一个1就可以了。

    所以这样递归下去即可。

    对于每个节点,如果是0,直接返回。如果是1:

     1、此节点是与门:取左右子树的和。

     2、此节点是或门:取左右子树中花费最小的一个。

    出来第一个1后,以后每次改变状态,一步即可完成。

    (因为我们第一次寻找的是变成1的最少步骤,所以退回一步就会出来0,再进一步出来1,以此类推)

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    using namespace std;
    int a[8200],n,T;
    string s;
    int ff(int ch,int rt)
    {
    	if (rt*2>=n) 
    	{
    	  if (ch==1) 
    	   {
    	     if (a[rt]==1) return 2;
             return 1;
    	   }
    	  else return 0;
        }
        if (ch==0) return 0;
        if (a[rt]==1) 
         return ff(1,rt<<1)+ff(1,rt<<1|1);
    	if (a[rt]==0)
    	 return min(ff(1,rt<<1),ff(1,rt<<1|1));
    }
    int main()
    {
       freopen("pla.in","r",stdin);
       freopen("pla.out","w",stdout);
       scanf("%d",&T);
       while (T--)
       {
       	cin>>n>>s;
       	int le=s.length(),q=0;
        for (int i=1;i<n;i++)  scanf("%d",&a[i]);
    	while (s[q]=='0') q++;
    	int bs=ff(s[q],1);
       	for (int i=q+1;i<le;i++) 	if (s[i]!=s[i-1]) bs++;
       	printf("%d
    ",bs);
       }
    	return 0;
    }


  • 相关阅读:
    Java之装饰模式
    Sharding-jdbc(一)分库分表理解
    JVM(四)JVM的双亲委派模型
    JVM(三)JVM的ClassLoader类加载器
    JVM(二)JVM的结构
    JVM(一)JVM的概述与运行流程
    Redis随笔(六)RESP的协议规范
    Redis随笔(五)Jedis、jedisCluster的使用
    Collections.synchronizedList使用方法陷阱(1)
    Collections.synchronizedList使用方法
  • 原文地址:https://www.cnblogs.com/riskyer/p/3398168.html
Copyright © 2020-2023  润新知