• 南邮第八届程序设计竞赛之网络预选赛小结 一(错题集)


    帅神妹纸的生日礼物

    时间限制(普通/Java):1000MS/3000MS         运行内存限制:65536KByte

    比赛描述

        A协大牛帅神的妹纸最近又要过生日了,然而妹纸心里早已有一个想要的礼物,妹纸想要的礼物就是10种稀有的钻石,帅神为了满足妹纸的要求,四处打探知道了钻石在一个神秘的地方,这个地方有很多神,所有神灵站成一排,每个神手上有一种钻石,然而懒虫帅神为了少走路,想着尽可能少的访问相邻神,从他们手中获得钻石,已知妹纸对于每种钻石需求的数量多少,求问帅神需要最少访问多少连续的神才可以获得妹纸需要钻石。

    输入

    本题为多组样例,第一行输入一个整数t(t <= 100),表示样例个数,对于每组样例,

    第一行为一个由0-9数字组成的字符串组成(长度小于100,000),表示站成一排的神灵,每种数字代表该神拥有几号钻石

    第二行为10个数字,分别表示妹纸需要的0-9号钻石是多少

    输出

    每组样例输出一个数字,表示最少访问多少个连续的神可以满足妹纸需求,如果无法满足,输出"Let's break up"。

    样例输入

    2
    1234567890
    0 0 0 1 1 0 1 0 0 0
    1234567890
    2 0 0 0 0 0 0 0 0 0

     

    样例输出

    4
    Let's break up

    题目分析:典型的两点法,用st和ed维护一段区间,先找第一段符合条件的,然后缩小范围判断,不满足了再往后扩大范围

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    int const MAX = 100005;
    int const INF = 0x3fffffff;
    int need[15], has[15];
    char s[MAX];

    bool judge()
    {
        for(int i = 0; i < 10; i++)
            if(has[i] < need[i])
                return false;
        return true;
    }

    int main()
    {
        int T;
        scanf("%d", &T);
        while(T --)
        {  
            memset(has, 0, sizeof(has));
            scanf("%s", s);
            int len = strlen(s);
            for(int i = 0; i < 10; i++)
                scanf("%d", &need[i]);
            int st = 0, ed = 0, ans = INF;
            while(ed < len)
            {
                while(!judge() && ed < len)
                {
                    has[s[ed] - '0'] ++;
                    ed ++;
                }
                while(judge() && st < ed)
                {
                    ans = min(ans, ed - st);
                    has[s[st] - '0'] --;
                    st ++;
                }
            }
            if(ans == INF)
                printf("Let's break up ");
            else
                printf("%d ", ans);
        }  
    }

    小明的排队

                                                             时间限制(普通/Java):2000MS/6000MS         运行内存限制:65536KByte

    比赛描述

        TC是个土豪,经常给整个集训队发苹果,并且喜欢将大家排成一队根据每个人的苹果数量做出一些奇怪的事情,比如让每个人算出自己右边苹果数量比自己少的人的个数。拿别人的手短,大家对于TC的奇怪嗜好也只能牵就了。

    输入

    输入第一行为一个T(T <= 6)表示数据组数,每组数据包含整数n(n个人, 1<=n<=100000),以及n个整数(正整数,代表每个人相应的苹果数量)

     

    输出

    对于每组数据输出n个整数,第i个整数表示第i个人右边苹果比他的少的人的个数。

    样例输入

    1
    4 5 2 6 1

     

    样例输出

    2 1 1 0

    提示

    输入请用scanf,输出请用printf

    输出数据的最后一个数字后面也有空格

    题目分析:典型的逆序数问题,归并排序和树状数组都可以做

    #include <cstdio>
    #include <cstring>
    int const MAX = 1e5 + 5;
    int const INF = 0x7FFFFFFF;
    int n, a[MAX], res[MAX];

    struct DATA
    {
        int val, idx;
    }d[MAX], a1[MAX], a2[MAX];
       
    void merge_sort(int l, int mid, int r, DATA *d)
    {
        int len1 = mid - l;
        int len2 = r - mid;
        for(int i = 0; i < len1; i++)
            a1[i] = d[i + l];
        a1[len1].val = INF;
        for(int i = 0; i < len2; i++)
            a2[i] = d[i + mid];
        a2[len2].val = INF;
        int i = 0, j = 0, k = l, tmp = 0;
        while(i < len1 || j < len2)
        {
            if(a1[i].val <= a2[j].val)
            {
                res[a1[i].idx] += tmp;
                d[k ++] = a1[i ++];        
            }
            else
            {
                if(a1[i].val != INF)
                    tmp ++;
                d[k ++] = a2[j ++];        
            }
        }
    }

    void Merge(int l, int r, DATA *d)
    {
        if(l == r - 1)
            return;
        int mid = (l + r) >> 1;
        Merge(l, mid, d);
        Merge(mid, r, d);
        merge_sort(l, mid, r, d);
    }

    int main()
    {
        int T;
        scanf("%d", &T);
        while(T --)
        {
            memset(res, 0, sizeof(res));
            scanf("%d", &n);
            for(int i = 0; i < n; i++)
                scanf("%d", &a[i]);
            for(int i = 0; i < n; i++)
            {
                d[i].val = a[i];
                d[i].idx = i;
            }
            Merge(0, n, d);
            for(int i = 0; i < n; i++)
                printf("%d ", res[i]);
            printf(" ");
        }
    }

    Money

    时间限制(普通/Java):1000MS/3000MS         运行内存限制:32768KByte

    比赛描述

        土豪BJ当前身上有现金x元,为了接济他的穷diao基友Tc,他对Tc说你现在可以交换我当前现金的任意两个相邻数字最多k次,多出来的钱都给你,Tc想知道自己最多能得到多少现金。

    输入

    输入第一行为一个整数T代表数据组数,每组数据只有一行包括两个数字x和k,数字均不含前导零

    (1 <= T <= 15, 1 <= x <= 1019, 0 <= k <= 100)

    输出

    对每组数据,输出一个数字表示Tc能得到的最多现金数。

    样例输入

    3
    1399 3
    256 1
    109009 4

     

    样例输出

    7920
    270
    801891

    题目分析:尽量让高位的数字大,从最高位开始向低位找,先找到k步之内的最大数,如果k步之内的最大数不是当前位置的数,那么把最大数交换到当前为止,然后减去初始值即可,因为没有负数,可以直接I64u

    #include <cstdio> 
    #include <cstring> 
    #include <algorithm>
    #define ull unsigned long long 
    using namespace std;
    char s[20]; 
    int k; 
     
    int main() 

        int T;
        scanf("%d", &T);
        while(T --)
        {
            scanf("%s %d", s, &k);
            ull bj_cash, tc_cash;
            sscanf(s, "%I64u", &bj_cash);
            int len = strlen(s), now;   
            for(int i = 0; i < len; i++) 
            { 
                now = i; 
                for(int j = i + 1; j <= i + k && j < len; j++) 
                    if(s[j] > s[now]) 
                        now = j; 
                if(now != i) 
                { 
                    for(int j = now; j > i; j--) 
                    { 
                        swap(s[j], s[j - 1]); 
                        k --;
                    }
                 }   
            }
            sscanf(s, "%I64u", &tc_cash);
            printf("%I64u ", tc_cash - bj_cash); 
        } 
    }

     
  • 相关阅读:
    基础知识漫谈(5):应用面向对象来分析“语言”
    【线段树】BZOJ2752: [HAOI2012]高速公路(road)
    【树状数组】BZOJ3132 上帝造题的七分钟
    【AC自动机】Lougu P3796
    【Splay】bzoj1500(听说此题多码上几遍就能不惧任何平衡树题)
    【fhq Treap】bzoj1500(听说此题多码上几遍就能不惧任何平衡树题)
    【可持久化线段树】POJ2104 查询区间第k小值
    【RMQ】洛谷P3379 RMQ求LCA
    【倍增】洛谷P3379 倍增求LCA
    【网络流】POJ1273 Drainage Ditches
  • 原文地址:https://www.cnblogs.com/yfz1552800131/p/5398408.html
Copyright © 2020-2023  润新知