UVA-11491 Erasing and Winning (单调队列)

题目大意:给一个数字(开头非0),拿掉其中的d个数字,使剩下的数字最大(前后顺序不能变)。

题目分析:拿掉d个数字,还剩下n-d个数字。相当于从n个数字中按先后顺序选出n-d个数字使组成的数字最大,当然采用窗口滑动优先选取大的。

代码如下:

# include<iostream>
# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;

struct Num
{
    int val,id;
};
Num num[100005],que[100005];
char p[100005];
int vis[100005];

void solve(int k,int l)
{
    int head=0,tail=-1;
    for(int i=0;i<k-1;++i){
        while(head<=tail&&que[tail].val<num[i].val)  --tail;
        ++tail;
        que[tail]=num[i];
    }
    int id=-1;
    for(int i=k-1;i<l;++i){
        while(head<=tail&&que[tail].val<num[i].val) --tail;
        ++tail;
        que[tail]=num[i];
        while(que[head].id<i-k+1||que[head].id<=id) ++head;
        printf("%d",que[head].val);
        id=que[head].id;
    }
    printf("\n");
}

int main()
{
    int n,d;
    while(scanf("%d%d",&n,&d)&&n+d)
    {
        scanf("%s",p);
        int l=strlen(p);
        for(int i=0;i<l;++i)
            num[i].val=p[i]-‘0‘,num[i].id=i;
        solve(d+1,l);
    }
    return 0;
}

  

时间: 2024-10-13 20:23:15

UVA-11491 Erasing and Winning (单调队列)的相关文章

UVA 11491 Erasing and Winning

#include<bits/stdc++.h> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; typedef long long ll; const int maxn=1000100; const int INF=1

【思路、优化】UVa 11491 - Erasing and Winning

Juliano is a fan of the TV show Erasing and Winning, where participants are selected in a draw and receive money for taking part in the show. In the show, the presenter writes a number of N digits in a board. The participant must then erase exactly D

UVA 11491 Erasing and Winning 奖品的价值 (贪心)

题意:给你一个n位整数,让你删掉d个数字,剩下的数字要尽量大. 题解:因为最后数字位数是确定的,而且低位数字对答案的贡献是一定不及高位数字的,所以优先选择选最大且最靠左边的数字,但是有一个限制,选完这个数字以后右边剩下的数字要保证足够接下来的选择,所以我想到了优先队列,记录一个信息,选的数字所在的位置,以及上一个数字所在的位置,如果当前出队的数字在上一个选的位置前面就直接丢掉,每次选完一个以后剩下要选的数字就减少了,满足限制的条件的数字会增加,再把新的待选数字加入队列. #include<bit

UVa 11491 Erasing and Winning 题解

难度:α 用时:30 min 题目:?? 这是个裸贪心题. 题目要求在某数字字符串中删去给定个数的字符,使剩下来的数字最大. 那么不难想到用队列.线性复杂度.0 ms. 每读入一个数,就把之前比较小的拿掉. 注意不能拿太多,否则长度不够. 队满了也不能继续放.(除非有更大的元素可以把队尾的怼下去) 1 for (int i = 0; i < d; i++) { 2 char c = getchar(); 3 while (it > 0 && ans[it] < c &am

uva 11491:Erasing and Winning(贪心)

题意:给一个长n(n<10^5)位的数,删除d位,求删除后最大的数.(原数无前导0) 思路:从前往后扫,如果a[i] > a[i-1],则删除a[i-1].我暴力的用链表实现了…… #include <cstdio> #include <cstring> #include <cstdlib> #include <list> using namespace std; #define N 100020 char str[N]; int main()

UVA Live Achrive 4327 Parade (单调队列,dp)

容易想到dp[i][j]表示在第i行j个路口的开始走最大高兴值. 每次可以向左走,或者向右边走,然后向北走.(或者直接往北) 向左走到,状态转移为dp[i][j] = dp[i][k] + happy[i][k][j](为了方便处理,i从1开始编号,0行dp值存0) 处理出前缀和,happy[i][k][j]表示为sum[i][j] - sum[i][k] 向左走应该取max(dp[i][k]-sum[i][k]) k应该满足time[i][k][j] <= k 随着j的变化k的范围是一个滑动窗

11491 - Erasing and Winning(贪心)

一开始真的没想到这竟然是一道贪心题目.  不过后来仔细想想也就明白了. 我采取的做法是自前向后扫一遍,用一个指针rear动态维护答案数组中的最后一个元素,如果遇到一个比它大的数s[i],那么从它开始将它及其它之前的比s[i]小的数全部删除,并且用变量cnt记录删除的个数, 防止删除多了. 对于贪心算法的正确性我们不难用反证法来证明: 假设这样做不是最优的,那么如果不这样做,对于一个长度一定的答案,得到的结果一定小于这样做的结果. 但是还有可能少删了,也就是第三组样例那种情况,所以我们贪心结束后要

UVA-1619 Feel Good (单调队列)

题目大意:给一个非负整数序列,求出一个使得区间和乘以区间最小值最大的区间. 题目分析:单调队列.维护两个数组,l[i]表示以a[i]为最小值的左半区间的最左边端点,r[i]表示以a[i]为最小值的右半区间的最右边端点,l[i]和r[i]合起来便是以a[i]为最小值的整个区间.枚举一遍 i 即可. 注意:UVA上的这道题有个大大的坑,明明说可以输出任意一个区间(多个解时),实际上是骗人的!!! 代码如下: # include<iostream> # include<cstdio> #

台州 OJ 3847 Mowing the Lawn 线性DP 单调队列

描述 After winning the annual town competition for best lawn a year ago, Farmer John has grown lazy; he has not mowed the lawn since then and thus his lawn has become unruly. However, the competition is once again coming soon, and FJ would like to get

2014 Super Training #2 C Robotruck --单调队列优化DP

原题: UVA 1169  http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3610 大白书上的原题. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algor