zoukankan      html  css  js  c++  java
  • [每日一题2020.06.11]Codeforces Round #644 (Div. 3) H

    A-E见 : 这里

    题目

    我觉得很有必要把H拿出来单独发( 其实是今天懒得写题了 )

    problem H

    一个从 1 到 $ 2^m - 1$ 的长度为m的连续二进制序列, 删去指定的n个数, 问剩余的数的中位数是多少

    看了题解还琢磨了一个小时才懂, 绝不能跟着题目傻傻的暴力来写

    主要的思想还是动态调整的思想

    首先比如我们制定m = 3

    得到一串序列转换为十进制就是 0 1 2 3 4 5 6 7, 该怎么删才能在不用遍历的情况下找到中位数呢?

    ( 这题肯定不能暴力, 给定的m = 60, $ 2^{60} = 1152921504606846976 $ )

    我们这里用一种动态维护的方式 :

    比如n=3, m=3, 删去001, 011, 111

    1. 先不管三七二十一, 删去最末尾的那n个数, 判断假设这样删除的话最后的中位数是几

    1591835717892

    1. 将删除队列从小到大排序, 依次维护调整 比如这里是1, 3, 7
    2. 假如删除的为比目前所指向的值大的数, 则不用调整 why ? 见图 :

    1591836286972

    ​ 可以看到, 只要删除的数是比目前所指向的大的数, 中位数都是现在这个数, 不用变.

    1. 假如删除的为小于或等于目前所指向的值的数, 则指针++ why ? 见图 :

    1591837201608

    ​ 比如我们删除1, 那么相当于原本假设的删除的最后三个数少了一个, 前面增加了一个, 则删除后序列的中间值为现在的值+1 .

    ​ 我们将3, 7继续删除 :

    1591837399667

    1591837408891

    由于原本的值是从0连续的, 所以直接输出最后指针pos的值的二进制形式即为答案.

    tips : 见到这种题, 一定要好好想想位置的计算, 很容易出现错误 !

    pos的位置 :

    1591839927632

    ac代码 :

    /*
     * Author: RoccoShi
     * Time: 2020-06-10 20:05:02
    */
    
    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    ll a[105];
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0);
        int t;
        cin >> t;
        while(t--) {
        	int n, m;
        	cin >> n >> m;
        	for (int i = 0; i < n; ++i)
        	{
        		string s;
        		cin >> s;
        		ll tmp = 0;
        		for (int j = 0; j < m; ++j)
        		{
        			tmp = tmp*2 + s[j] - '0'; // 二进制 --> 十进制
           		}
           		a[i] = tmp;
        	}
        	sort(a, a + n);
        	ll pos = ((1ll<<m)-1-n) / 2;
        	for (int i = 0; i < n; ++i)
        	{
        		if(a[i] <= pos)
        			pos++;
        	}
        	string ans(m,'0');
        	for(int i = m-1; i >= 0; --i) { // 十进制 --> 二进制
        		ans[i] = (pos & 1) + '0';
        		pos >>= 1;
        	}
        	cout << ans << endl;
        }
        return 0;
    }
    
    

    这里注意下十进制二进制的相互转换代码 ( 建 议 背 诵 ) :

    int x = 0;
    for (int j = 0; j < m; ++j)
    {
        x = x*2 + s[j] - '0'; // 二进制s --> 十进制x
    }
    
    for(int i = m-1; i >= 0; --i) 
    { 
        ans[i] = (pos & 1) + '0'; // 十进制 --> 二进制
        pos >>= 1;
    }
    
  • 相关阅读:
    Aptana 安装jQuery库 智能提示
    .NET Core 微服务—API网关(Ocelot) 教程 [三]
    .NET Core 微服务—API网关(Ocelot) 教程 [二]
    NuGet 应用指南
    记一次 Microsoft.Bcl.Async 使用经验
    认证授权:学习OAuth协议
    深入了解MFC中的文挡/视结构
    (VC)MDI工程中,在自定义类中调用文档类的函数
    MFC中的指针
    XP IIS5.1安装文件
  • 原文地址:https://www.cnblogs.com/roccoshi/p/13091473.html
Copyright © 2011-2022 走看看