zoukankan      html  css  js  c++  java
  • 【IOI2018】组合动作

    还是自己水平不够,想了两天没想出来……(然后我就被其他人吊打了)

    这种题目看了题解就秒会,自己想就想不出来……

    下面是我的心路历程(我就在想出来又叉掉的不断循环中度过……)

    开始把题目看成了查询限制 (2N) 长度,然后怎么也不会做,看看题,发现是 (4N) (然而还是不会做)

    首先一个很显然的想法,就是先两步找出第一个,然后后面的每个都用一步。最后一位可能要多耗费一个。此时总步数正好是 (N + 2)

    然后重点就在中间的了。

    我们记剩下来的字符为 (A, B, C),当前处理好的字符串为 (S)

    首先很容易有一个想法:在一个串后面加一堆同一个字符,然后看增加了多少,这样有概率一下子增加多个。

    如果把所有连续的长度求出来,那么每次枚举只有两种情况,貌似很优秀。

    于是构造 ({ S + A + dots, S + B + dots}),发现没填满,应该不对,于是改成 ({ S + A + A + dots, S + A + B +dots, S + B + A + dots, S + B + B + dots })

    然后发现对于下面是 (A)(B) 的都很好求,只要分类讨论增加了几个。

    但是一旦有 (C) 就会有额外枚举量,所以这种想法放弃了。

    接着考虑如果不求最长连续的,对三种情况暴力算的也许可以。比如说可以改成不断的求子问题的模型。

    仔细分析发现这样做本质和每次只增加 (O(1)) 个字符是相同的。

    所以考虑每次增加那么多。

    接下来我类似地考虑了这个加同一个字符。

    也就是询问 ({ S + A + A + A, S + A + B + B, S + B + A + A, S + B + B + B })

    显然也可以通过分类讨论加了多少个的情况。

    对于没加的;显然是 (C),对于加了 (1) 的,枚举第一位就可以知道第 (2) 位;对于加了 (3) 的,显然可以查询两次得到。对于这几种情况,得到每一个的耗费都是 (1)

    然而这个做法还是挂在加了 (2) 的,冷静分析,发现直接确定第三位还是更优的,但是马上发现你要用两步确定 (8) 种情况,然后GG。

    所以发现我的做法对于只增加了两个的都凑不出来(总会多一步)。

    凑了那么多,发现最后还是要找一个对于所有位数,情况平均少一点的。但是有一个 (3) 就显得难做了。


    直到我看了题解:

    我的做法太贪了,一次确定多位不太行,没有去想一次只确定一位……(这个故事告诉我们,做题尽量由浅入深,从简单的开始考虑)

    和分类讨论加了多少个的思想类似,这个十分的暴力……

    直接把下一个是 (A)(+2), 是 (B)(+1), 是 (C)(+0),显然这个很好构造 ({ S + A + A, S + A + B, S + A + C, S + B})

    显然满足。

    然后注意对剩下的只有一个的特判,正好补上最后的多的一个。

    然后我把 (<) 写成 (leq),WA了一发……

    #include "combo.h"
    
    const char sx[] = {'A', 'B', 'X', 'Y'};
    std::string S, li[3];
    std::string d(int at) {
    	return at == 3 ? S : li[at];
    }
    template<typename ... T> 
    std::string d(int at, T ... args) {
    	return (at == 3 ? S : li[at]) + d(args...);
    }
    std::string guess_sequence(int N) {
    	char fir = press("AB") >= 1 ? (press("A") ? 'A' : 'B') : (press("X") ? 'X' : 'Y');
    	S += fir; int bx = 0;
    	for (int i = 0; i < 4; ++i)
    		if (sx[i] != fir) li[bx++] = std::string(1, sx[i]);
    	for (bx = 1; bx < N; ) {
    		std::string qry;
    		if (bx + 1 == N) {
    			S += press(d(3, 0)) == N ? li[0] : (press(d(3, 1)) == N ? li[1] : li[2]);
    			break;
    		}
    		int res = press(d(3, 0, 0, 3, 0, 1, 3, 0, 2, 3, 1)) - bx;
    		if (!res) S += li[2];
    		else if (res == 1) S += li[1];
    		else if (res == 2) S += li[0];
    		++bx;
    	}
    	return S;
    }
    
    
  • 相关阅读:
    使用C#调用系统API实现锁定计算机
    阶段性总结
    心情状态所困
    VMware虚拟机网络配置相关备忘
    数据库学习第一篇
    给window xp sp2设置共享文件夹
    转报竞赛实操试题
    数据库视频笔记
    Android开发从零开始,搭建交叉编译环境
    排故总结
  • 原文地址:https://www.cnblogs.com/daklqw/p/11587206.html
Copyright © 2011-2022 走看看