集训题解-Day2

集训题解-Day2

A.GG的。。。(我tm实在懒得想背景了)

题目描述

描述
给出一段序列,选出其中连续且非空的一段使得这段和最大。

输入
多组数据
first line:n(1<=n<=2e5)
next line:n个整数(绝对值小于等于1e4)

输出
每组输出一个整数()

样例输入1
7
2 -4 3 -1 2 -4 3
样例输出1
4

解答

经典的”最大连续子段和”问题。我这里用dp来做:设dp[i]为以第i个数结尾的最大连续子段和,则dp[i] = max(a[i], dp[i-1]+a[i]);

const int maxn = 100010;
int d[maxn], a[maxn];
int main()
{
    int n;
    while(scanf("%d", &n) == 1){
        rep1(i, n) scanf("%d", &a[i]);
        d[0] = -100000;
        rep1(i, n) d[i] = max(a[i], d[i-1] + a[i]);
        int ans = -100000;
        rep1(i, n) ans = max(ans, d[i]);
        printf("%d\n", ans);
    }
    return 0;
}

B.喜欢大数的GG

题目描述

描述
GG比较喜欢较大的整数

给了GG n个整数

GG想将这n个整数组成一个最大的整数,

求助于你(我tm哪知道他为啥求助与你)

例如给定3个整数13,313,343 可以组成整数13313343

但这三个整数组成的最大的整数是34331313

输入
多组数据
每组:
first line:n(1<=n<=1000)
next line:n个整数(不小于1)

输出
对每组输入输出一个整数()

样例输入1
3
13 312 343
4
7 13 4 246
样例输出1
34331213
7424613

解答

直接对数字进行排序,关键在于对排序关键字的设置。
我采用的cmp函数:要比较的两个字符串设为s1和s2,若s1+s2(拼接)比s2+s1大,就让s1+s2排在前面。

B.不会分糖果的GG

题目描述

描述
自从迷恋上lz小姐姐,GG一直在追求lz小姐姐

有一天lz小姐姐给GG一个任务,给小朋友分糖果

智障的GG不会分糖果,总共有n个小朋友,本来lz小姐姐给GG的糖果刚好够均分给n个小朋友

但是GG很任性,xjb分了一番,所以现在小朋友手里的糖果多少不一

现在lz小姐姐很恼火,只能重新分配,但是小朋友都不喜欢让糖果减少所以。。。要让你来解决这个问题了

有n个小朋友分别标号为1-n,只能从每个小朋友移若干个糖果到编号相邻的小朋友那,每次移动都会使小朋友们的不高兴值+1(初始为0),其中编号1的只能移到编号2上,编号n的只能移到编号n-1上。

让你求当小朋友的糖果分配均匀后,不高兴值最低为多少

输入
多组输入数据
对于每组输入数据
第一行是一个整数n(小于10000)
接下来一行是n个整数(小于1000)分别代表n个小朋友的手里的糖果数量

输出
每组输入输出一个整数,

样例输入1
2
2 0
4
9 8 17 6
样例输出1
1
3

解答

设xi是第i个人分给第i+1个人的糖果数量,则由于每个人的最终糖果数量已知,可以列出n个关于每个人拿到的糖果数量的方程,而未知数只有n-1个,解之即可。

const int maxn = 10010;
int a[maxn], b[maxn], s, n;
int main()
{
    while(scanf("%d", &n) == 1){
        rep1(i, n) scanf("%d", &a[i]);
        int sum = 0; rep1(i, n) sum += a[i];
        s = sum / n;
        rep1(i, n) b[i] = a[i] - s + b[i-1];
        int ans = 0;
        rep1(i, n-1) if (b[i] != 0) ++ans;
        cout<return 0;
}

E.懒得想题面的栗子

题目描述

描述
给定一个仅由大写字母构成的字符串,现在有一个新的起始为空的字符串。

每次你可以把原字符串的首字母或尾字母移动到新的字符串的末尾。

要求新的字符串字典序最小。

输入
若干行,每行一个字符串,长度不超过100.

输出
若干行,对于每行输入,输出字典序最小的字符串。

样例输入1
ACDBCB
样例输出1
ABCBCD

解答

贪心。动态维护剩下的字符串,每次从头和尾当中选出较小的那一个即可。然而如果头和尾相同,则比较头后面的字符和尾前面的字符,若再相同则继续进行比较。

char s[2010];
int n,cnt;
int main()
{
    read(n);cnt=0;
    REP(i,n) scanf(" %c",&s[i]);
    int l=0,r=n-1;
    while(l<=r){
        int flag=0;
        for(int i=l;i<=r;i++)
        if (s[i]!=s[l+r-i]){
            flag=s[i]1:0;
            break;
        }
        if (flag) putchar(s[l++]);
        else putchar(s[r--]);
        cnt++;
    }
    return 0;
}

F.喜欢合并数的GG

题目描述

描述
GG又遇到了问题

给一个含有n个数的数组a,合并其中m个数的花费是这些数的和,一直合并,求最终合并成一个数的花费最小是多少。(每次合并可以少于m个但不可大于)

qzyn

输入
多组数据
对于每组数据
第一行是两个整数n,和m(2<=n<=1e5,2<=m<=n)(m指每次做多合并m个数)
接下来是n个整数ai(ai<=1e6)

输出
对于每组输入,输出一个整数,即最小花费

样例输入1
2
2
1 1
3
2
1 2 3
样例输出1
2
9

解答

类似哈夫曼编码。直接维护一个优先队列,每次取出最小的m个数,累加后放回优先队列。
不用担心复杂度的问题,看似m很大的时候每次操作都需要大量的取操作,但事实上这样也无需几次操作了。每个元素一旦被取出,就不会再自己回到队列了。

你可能感兴趣的:(集训题解-Day2)