zoukankan      html  css  js  c++  java
  • [日常摸鱼]算是一些思维题-CF680D/Hamming Code

    https://codeforces.com/contest/680/problem/D

    你需要确定一个(X(Xleq m))(mleq 10^{15}),每次操作会找一个最大的不超过(X)(a^3),然后把(X)变成(X-a^3),直到为0,问最多能操作多少次,以及在操作次数最多的情况下(X)最大是多少?

    考虑对于一个规模为(m)的问题(我们同样是自己选(Xleq m)),考虑怎么转换成一个规模更小的问题:

    对于当前的(X),每次会选出最大的是(a:a^3leq X,(a+1)^3>X),后面那个也就是(Xleq (a+1)^3-1)

    • (1)如果接下来的操作直接挖掉一个(a^3),那我们就可以直接取(X=m),问题转化成规模为(m'=m-a^3)的问题。

    • (2)如果接下来的操作挖掉大小的是((a-1)^3),那就会有约束((a-1)^3leq X),和(a^3>X),也就是(Xleq a^3-1),注意到这么一件事情:规模越大的问题可以转移到的子问题的集合也会越大(因为只要(Xleq m)就好了),所以我们贪心地选取(X=a^3-1),问题转化成(m'_1=a^3-1-(a-1)^3=3a^2-3a=3a(a-1)geq 0)

    • (3)以此类推,对于这一次操作挖掉((a-t)^3)的情况,问题会转化成(m_t'=(a-t+1)^3-1-(a-t)^3)

    对于(2)和(3)我们似乎可以稍微比较一下哪个决策会更优:

    (egin{aligned}m'_1-m'_t&=a^3-(a-t+1)^3-[(a-1)^3-(a-t)^3]\&=(t-1)[a^2+a(a-t+1)+(a-t+1)^2]-(t-1)[(a-1)^2+(a-1)(a-t)+(a-t)^2]\&=2(t-1)(2a-t)end{aligned})

    对于(tgeq 2)(t-1> 0),同时我们上面讨论的是挖掉一个((a-t)^3>0)的情况,就会有(2a-t>0),所以(m_1'>m_t'),(2)对应的情况会比(3)的情况来得优,所以只要考虑(1)和(2)的情况就行啦~​

    void dfs(ll m,int block,ll X){
    	if(m==0){
    		if(block>=r1){
    			if(block==r1)r2=max(r2,X);
    			else r2=X;
    			r1=block;
    		}
    		return;
    	}
    	ll a=1;
    	while(calc(a+1)<=m)a++;
    	dfs(m-calc(a),block+1,X+calc(a));
    	dfs(calc(a)-1-calc(a-1),block+1,X+calc(a-1));
    }
    

    复杂度是O(能过)。

    考虑怎么分析这东西的复杂度,对于(1)的决策,我们的(a)满足:(a^3leq mleq (a+1)^3-1),一次操作后变成(m-a^3),上界是((a+1)^3-a^3-1=3a^2+3a),这似乎说明一个(O(a^3))规模的问题会变成(O(a^2))规模的问题,也就是一个(O(m))级别的问题会变(O(m^{2/3}))级别的问题,每次在次数上乘个(frac{2}{3}),多少次会达到(m=1)?也就是(m^{(frac{2}{3})^t}=1),最后(t)(O(log log m))级别的,确实是O(能过)(雾)。同时对于(2)的决策也是一样的情况,于是整个算法都是O(能过)的啦(

    $ $

    另一个是之前比赛的一场,翻以前笔记的时候刚好翻到,就也连着发出来。

    https://codeforces.com/group/TBxCTUW7hQ/contest/309674/problem/H

    Hamming Code,长度为(2^k)的二进制码,从0开始标号,纠错码是所有2的幂次的位置和位置0,纠错码(d(2^j)=oplus_{iand2^{j} eq 0,i eq 2^j}d(i))(也就是(2^j)的贡献来自所有二进制表示下(2^j)有数字的位置,(d(0))是所有其他位的异或和。保证错误不超过2个,一个汉明码(kleq 16),判断是否有错,有的话有几个地方错,如果只有一个地方错了,指出哪里错

    Hamming Code真是神奇…

    注意0是所有其他位置的异或和,首先对非纠错码位置,可以(O(nlog n))地求出对应纠错码的值,如果发现有地方不一样,判断(d(0))是否相等,如果相等的话直接说明有两个地方错了,否则能确定只有一个地方有错,再对所有纠错码考虑贡献:

    int res=0;
    rep(i,0,k-1)if(s[1<<i]!=t[1<<i])res+=(1<<i);
    

    一个类似的问题是小鼠试毒。

    小鼠试毒:有(n)瓶水,只有其中一个有毒,小鼠一旦喝到有毒的24小时后会死,问至少要几只小鼠才能在24小时后一次找到这瓶毒药。

    仿照Hamming Code,先对瓶子标号然后二进制拆分,设(x=(a_ka_{k-1}dots a_0)_2),第一只小鼠喝下所有(a_0=1)的药水,第二只喝下所有(a_1=1)的…以此类推,一共(k+1)只小鼠就能确定位置。同时换成其他进制就没法这么表示了,于是这也是最小次数。

  • 相关阅读:
    Selenium IDE的第一个测试用例——路漫长。。。
    selenium学习第三天,新建一个测试用例(运行失败)。
    Selenium学习第二天,了解Selenium工作模式与学习Selenium需要具备的知识与工具。
    了解Selenium与自动化测试第一天“云里雾里”
    javascript冷知识
    HTTP权威指南学习心得
    (六)Linux进程调度-实时调度器_学习笔记
    (五)Linux进程调度-CFS调度器_学习笔记
    (四)Linux进程调度-组调度及带宽控制_学习笔记
    (三)Linux进程调度器-进程切换_学习笔记
  • 原文地址:https://www.cnblogs.com/yoshinow2001/p/14630315.html
Copyright © 2011-2022 走看看