• A Magic Lamp HDU


    原文地址:https://blog.csdn.net/acdreamers/article/details/8692384

    题意:

    对于一个序列A[1...N],一共N个数,除去M个数使剩下的数组成的整数最小。

    也就是说在A[1...N]中顺次选取N-M个数,使值最小。

    本题很有技巧性,一开始我总是想不明白,后来在纸上画了一下,大概明白了是怎么回事。

    它主要是基于以下事实:

    对于序列A[1...N],选取N-M个数,使组成的值最小,而且顺序不能交换,既然要选取N-M个,那么可以容易知道这N-M位数的第一位一定在数组A中的区间

    [1,M+1]中出现,为什么是这样呢?

    我们可以这样来模拟一下:假设A数组就只有6个数,分别是A[1],A[2],A[3],A[4],A[5],A[6],我们去掉M=2个数,使形成的值最小。

    那么我们此时的N=6,M=2,N-M=4

    则我们说形成的4位数的第一位一定在区间[1,3]中出现,因为如果区间范围再大点,比如[1,4],这样就不科学了,因为第一位一定不会是A[4],更不会是

    A[5],A[6],我们假设可以是A[4],那么后面只有A[5],A[6]两位数了,这样的话最多只可能形成3位数,绝对不能形成N-M=4位了。

    当然到了这里,我们就可以这样做了,第一位可以在区间[1,M+1]里面找,假设第一位在位置x,因为第二位肯定在第一位的后面,所以第二位一定存在于

    区间[x+1,M+2],为什么是M+2,因为第一位已经确定了,现在只需要确定N-M-1位了,所以区间就可以向后增加1,一直这样循环下去,就可以找到了。

    #include <iostream>
    #include <cstdio>
    #include <sstream>
    #include <cstring>
    #include <map>
    #include <set>
    #include <vector>
    #include <stack>
    #include <queue>
    #include <algorithm>
    #include <cmath>
    #define rap(i, a, n) for(int i=a; i<=n; i++)
    #define rep(i, a, n) for(int i=a; i<n; i++)
    #define lap(i, a, n) for(int i=n; i>=a; i--)
    #define lep(i, a, n) for(int i=n; i>a; i--)
    #define MOD 2018
    #define LL long long
    #define ULL unsigned long long
    #define Pair pair<int, int>
    #define mem(a, b) memset(a, b, sizeof(a))
    #define _  ios_base::sync_with_stdio(0),cin.tie(0)
    //freopen("1.txt", "r", stdin);
    using namespace std;
    const int maxn = 1001, INF = 0x7fffffff;
    int d[maxn][10];
    char a[maxn], num[maxn];
    int n, m;
    
    int minn(int i, int j)   //核心
    {
        return a[i] <= a[j] ? i : j;
    }
    
    int rmq(int l, int r)
    {
        int k = 0;
        while((1<<(k+1)) <= r-l+1) k++;
        return minn(d[l][k], d[r-(1<<k)+1][k]);
    }
    
    
    int main()
    {
        while(~scanf("%s%d", a, &m))
        {
            int len = strlen(a);
            n = len;
            m = len - m;
            for(int i=0; i<n; i++)  //下标的序列
                d[i][0] = i;
            for(int j=1; (1<<j) <= n; j++)
                for(int i=0; i+(1<<j)-1 < n; i++)
                    d[i][j] = minn(d[i][j-1], d[i+(1<<(j-1))][j-1]);
            int i, j;
            i = j = 0;
            while(m--)
            {
                i = rmq(i, len - m - 1);  //while中m已经--了所以例如第一次就相当于0到m去找第一位
                num[j++] = a[i++];
            }
            for(i=0; i<j; i++)
                if(num[i] != '0') break;
            if(i == j)
            {
                puts("0");
                continue;
            }
            while(i < j)
            {
                printf("%c", num[i]);
                i++;
            }
            printf("
    ");
        }
    
        return 0;
    }
    自己选择的路,跪着也要走完。朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。
  • 相关阅读:
    QT内置的ICON资源
    Spark源代码阅读笔记之MetadataCleaner
    Android API Guides---Bluetooth
    做一个WINDOWS下破解WIFI。不须要Linux抓包!
    CPU GPU设计工作原理《转》
    杭电 1280 前m大的数
    机房收费系统——报表(2)
    概览C++之const
    Android动态禁用或开启屏幕旋转工具
    shrink-to-fit(自适应宽度)
  • 原文地址:https://www.cnblogs.com/WTSRUVF/p/9451284.html
Copyright © 2020-2023  润新知