hihocoder 编程挑战赛75

题目1

内存限制:256MB

描述

H公司在北京和上海两个城市各有一间办公室。该公司最近新招募了2N名员工,小Hi负责把这2N名员工分配到北京和上海各N名。

 

于是小Hi调查了新员工对于北京和上海的意愿,我们用Bi和Si表示。Bi代表如果分配第i名员工去北京,他的满意指数;Si代表如果分配去上海,他的满意指数。

 

小Hi想知道如何分配才能使2N名员工的满意指数之和最高。

 

输入

第一行包含一个整数N。

 

以下2N行每行包含两个整数Bi和Si。

 

1 ≤ N ≤ 1000

 

0 ≤ Bi, Si ≤ 100000

 

输出

一个整数代表最高可能的满意指数之和。

 

测试样例

样例输入

2

100 50

80 80

50 100

10 30

样例输出

310

题解

#include <bits/stdc++.h>
using namespace std;
#define MAXN (1010)
static int B[2 * MAXN], S[2 * MAXN];
int sat[MAXN][MAXN];

int main() {
    int n;
    while (cin >> n) {
        memset(B, 0, sizeof(B));
        memset(S, 0, sizeof(S));
        for (int i = 1; i <= 2 * n; i++) {
            cin >> B[i] >> S[i];
        }
        memset(sat, 0, sizeof(sat));
        for (int i = 1; i <= n; i++) {
            sat[i][0] = sat[i - 1][0] + B[i];
            sat[0][i] = sat[0][i - 1] + S[i];
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                sat[i][j] = max(sat[i][j - 1] + S[i + j],
                sat[i - 1][j] + B[i + j]);
            }
        }
        cout << sat[n][n] << endl;
    }
    return 0;
}

 

题目2

内存限制:256MB

描述

H公司在北京、上海和纽约三个城市各有一间办公室。该公司最近新招募了3N名员工,小Hi负责把这3N名员工分配到北京、上海和纽约各N名。

 

于是小Hi调查了新员工对于北京、上海和纽约的意愿,我们用Bi、Si和Ni表示。Bi代表如果分配第i名员工去北京,他的满意指数;Si代表如果分配去上海的满意指数;Ni代表如果分配去纽约的满意指数。

 

小Hi想知道如何分配才能使3N名员工的满意指数之和最高。

输入

第一行包含一个整数N。

以下3N行每行包含两个整数Bi、Si和Ni。

1 ≤ N ≤ 100

0 ≤ Bi, Si, Ni ≤ 100000

输出

一个整数代表最高可能的满意指数之和。

样例

样例输入

2

100 50 100

80 80 100

50 100 100

10 30 100

80 40 30

20 70 50

样例输出

550

#include <bits/stdc++.h>
using namespace std;
#define MAXN (1010)
static int B[2 * MAXN], S[2 * MAXN];
int sat[MAXN][MAXN];

int main() {
    int n;
    while (cin >> n) {
        memset(B, 0, sizeof(B));
        memset(S, 0, sizeof(S));
        for (int i = 1; i <= 2 * n; i++) {
            cin >> B[i] >> S[i];
        }
        memset(sat, 0, sizeof(sat));
        for (int i = 1; i <= n; i++) {
            sat[i][0] = sat[i - 1][0] + B[i];
            sat[0][i] = sat[0][i - 1] + S[i];
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                sat[i][j] = max(sat[i][j - 1] + S[i + j],
                sat[i - 1][j] + B[i + j]);
            }
        }
        cout << sat[n][n] << endl;
    }
    return 0;
}

 

题目3

hihocoder #1818 : 顺子组合

 

问题来源URL

http://hihocoder.com/problemset/problem/1818

描述

你有一个包含N个整数的数组:A1, A2, ... AN。我们将3个或3个以上数值连续的整数序列称作顺子,例如[1, 2, 3]、[5, 6, 7, 8]和[10, 11, 12, 13, 14, 15, 16]都是顺子。

 

请你判断A数组是否能拆分成若干个顺子的组合。要求每个整数Ai恰好只属于其中一个顺子。

输入

第一行包含一个整数T代表测试数据的组数。  

每组数据第一行包含一个整数N  

每组数据第二行包含N个整数A1, A2, ... AN  

1 ≤ T ≤ 10  

1 ≤ N ≤ 10000  

0 ≤ Ai ≤ 100000

输出

对于每组数据输出YES或者NO代表是否能拆分成顺子组合。

测试样例

样例输入

2

7

4 1 3 2 5 4 6

8

4 1 3 2 5 4 6 6

样例输出

YES  
NO

题解

    顺子是扑克牌的一种排列顺序,指的是花色不一定相同的牌是一个连续的序列,该序列的长度还大于等于3。题目中的要求是让牌的划分序列每个的连续长度>=3。事实上,这个要求跟每个序列的长度都在3-5是等价的。如果能够满足3-5,则必然能满足>=3,因为3-5包含于>=3的情况;反过来,>=3的序列必然可以拆成3-5的序列。由于这个原因,我们找到了这个题的对应题目,http://codeforces.com/gym/101775/problem/J

    解决这道题,可以是按照如下思路:

    怎么把顺子合成一个序列,而不是拆分?显然,合成是非常简单的,顺子是一个表示个数的1序列,长度>=3,合成的话就是区间累加了。把它用差分序列表示的话,就是1,0,0,(至少有2个0)-1。最后得到的序列的差分,肯定是差分序列的叠加了。所以我们可以把它们累加起来,判断最后的和是否是等于0,并结合其他条件判定是多个顺子的组合。

代码

#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
int arr[MAXN];
int differ[MAXN];
int main() {
  int N, T;
  cin >> T;
  int a;
  for (int i = 0; i < T; i++) {
    cin >> N;
    memset(arr, 0, sizeof(arr));
    memset(differ, 0, sizeof(differ));
    int maxn = 0;
    for (int j = 0; j < N; j++) {
      cin >> a;
      maxn = max(a, maxn);
      arr[a]++;
    }
    for (int j = 0; j <= MAXN; j++) {
      differ[j + 1] = arr[j + 1] - arr[j];
    }
    differ[0] = arr[0];
    int t = 0;
    int sum = 0;
    for (int j = 0; j <= maxn; j++) {
      if (differ[j] > 0) sum += differ[j];
      if (j + 3 <= maxn + 1) {
        if (differ[j + 3] < 0) {
          sum += differ[j + 3];
          differ[j + 3] = 0;
        }
        if (sum < 0) break;
      }
    }
    #if 0
    for (int i = 0; i <= maxn; i++) {
      printf(" %d", differ[i]);
    }
    printf("\n");
    #endif
    if (sum != 0) {
      cout << "NO\n";
    } else {
      cout << "YES\n";
    }
  }
  return 0;
}

 

测试

3

3

0 1 2

1

10

7

0 1 2 3 9 10 11

7

0 1 2 3 5 6 8

>>Output:

YES

YES

NO

题目4

描述

请你实现一个加强版的栈,支持以下操作:

push x: 向栈顶加入一个整数x

pop: 从栈顶弹出一个整数,并且输出该整数

inc k x: 将处于栈底的前k个整数加x。

 

输入

第一行包含一个整数N,代表操作的数量。

以下N行每行一条操作。

1 ≤ N ≤ 200000, 0 ≤ x ≤ 100000, 1 ≤ k ≤ 当前栈的大小

 

输出

对于每一个pop操作,输出弹出的整数数值。

测试样例

样例输入

6

push 1

inc 1 2

push 2

inc 2 2

pop

pop

样例输出

4

5

题解

即使想用线段树也显得多余,因为在栈的操作中其实有一个很简单的特性就是每次只能pop一个,再加上问题中的条件是前k个增加值,所以并不会有需要利用线段树减少复杂度的情况。

代码

#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
int arr[MAXN];
int differ[MAXN];
int main() {
  int N, T;
  cin >> T;
  int a;
  for (int i = 0; i < T; i++) {
    cin >> N;
    memset(arr, 0, sizeof(arr));
    memset(differ, 0, sizeof(differ));
    int maxn = 0;
    for (int j = 0; j < N; j++) {
      cin >> a;
      maxn = max(a, maxn);
      arr[a]++;
    }
    for (int j = 0; j <= MAXN; j++) {
      differ[j + 1] = arr[j + 1] - arr[j];
    }
    differ[0] = arr[0];
    int t = 0;
    int sum = 0;
    for (int j = 0; j <= maxn; j++) {
      if (differ[j] > 0) sum += differ[j];
      if (j + 3 <= maxn + 1) {
        if (differ[j + 3] < 0) {
          sum += differ[j + 3];
          differ[j + 3] = 0;
        }
        if (sum < 0) break;
      }
    }
    #if 0
    for (int i = 0; i <= maxn; i++) {
      printf(" %d", differ[i]);
    }
    printf("\n");
    #endif
    if (sum != 0) {
      cout << "NO\n";
    } else {
      cout << "YES\n";
    }
  }
  return 0;
}

 

参考

http://codeforces.com/gym/101775/problem/J Straight Master

posted @ 2018-09-24 21:20  stackupdown  阅读(281)  评论(0编辑  收藏  举报