USACO 2018 US Open Contest, Silver

Problem 1. Out of Sorts

Keeping an eye on long-term career possibilities beyond the farm, Bessie the cow has started learning algorithms from various online coding websites.

Her favorite algorithm thus far is "bubble sort". Here is Bessie's implementation, in cow-code, for sorting an array A� of length N�.

sorted = false
while (not sorted):
   sorted = true
   moo
   for i = 0 to N-2:
      if A[i+1] < A[i]:
         swap A[i], A[i+1]
         sorted = false

Apparently, the "moo" command in cow-code does nothing more than print out "moo". Strangely, Bessie seems to insist on including it at various points in her code.

Given an input array, please predict how many times "moo" will be printed by Bessie's code.

INPUT FORMAT (file sort.in):

The first line of input contains N� (1≤N≤100,0001≤�≤100,000). The next N� lines describe A[0]…A[N−1]�[0]…�[�−1], each being an integer in the range 0…1090…109. Input elements are not guaranteed to be distinct. 

OUTPUT FORMAT (file sort.out):

Print the number of times "moo" is printed.

SAMPLE INPUT:

5
1
5
3
8
2

SAMPLE OUTPUT:

4

留意着农场之外的长期职业生涯的可能性,奶牛Bessie开始在不同的在线编程网站上学习算法。

她到目前为止最喜欢的算法是“冒泡排序”。这是Bessie的对长度为N�的数组A�进行排序的奶牛码实现。

sorted = false
while (not sorted):
   sorted = true
   moo
   for i = 0 to N-2:
      if A[i+1] < A[i]:
         swap A[i], A[i+1]
         sorted = false

显然,奶牛码中的“moo”指令的作用只是输出“moo”。奇怪的是,Bessie看上去执着于在她的代码中的不同位置使用这个语句。

给定一个输入数组,请预测Bessie的代码会输出多少次“moo”。

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

int N, B[100001];
pair<int,int> A[100001];

// Concise implementation of a binary indexed tree
void modify(int j) { for (; j<=N; j+=(j&-j)) B[j]++; }
int prefix_sum(int j) { int sum = 0; for (; j>0; j-=(j&-j)) sum += B[j]; return sum; }

int main(void)
{
  int answer = 1;
  cin >> N;
  for (int i=1; i<=N; i++) {
    int x; 
    cin >> x;
    A[i] = make_pair(x, i);
  }
  sort (A+1, A+N+1);
  for (int i=1; i<=N-1; i++) {
    modify(A[i].second);
    answer = max(answer, i - prefix_sum(i));
  }
  cout << answer << "\n";
  return 0;
}

Farmer John's N� cows (1≤N≤1051≤�≤105), numbered 1…N1…� as always, happen to have too much time on their hooves. As a result, they have worked out a complex social hierarchy related to the order in which Farmer John milks them every morning.

After weeks of study, Farmer John has made M� observations about his cows' social structure (1≤M≤50,0001≤�≤50,000). Each observation is an ordered list of some of his cows, indicating that these cows should be milked in the same order in which they appear in this list. For example, if one of Farmer John's observations is the list 2, 5, 1, Farmer John should milk cow 2 sometime before he milks cow 5, who should be milked sometime before he milks cow 1.

Farmer John's observations are prioritized, so his goal is to maximize the value of X� for which his milking order meets the conditions outlined in the first X� observations. If multiple milking orders satisfy these first X� conditions, Farmer John believes that it is a longstanding tradition that cows with lower numbers outrank those with higher numbers, so he would like to milk the lowest-numbered cows first. More formally, if multiple milking orders satisfy these conditions, Farmer John would like to use the lexicographically smallest one. An ordering x� is lexicographically smaller than an ordering y� if for some j�, xi=yi��=�� for all i<j�<� and xj<yj��<�� (in other words, the two orderings are identical up to a certain point, at which x� is smaller than y�).

Please help Farmer John determine the best order in which to milk his cows.

INPUT FORMAT (file milkorder.in):

The first line contains N� and M�. The next M� lines each describe an observation. Line i+1�+1 describes observation i�, and starts with the number of cows mi�� listed in the observation followed by the list of mi�� integers giving the ordering of cows in the observation. The sum of the mi��'s is at most 200,000200,000.

OUTPUT FORMAT (file milkorder.out):

Output N� space-separated integers, giving a permutation of 1…N1…� containing the order in which Farmer John should milk his cows.

SAMPLE INPUT:

4 3
3 1 2 3
2 4 2
3 3 4 1

SAMPLE OUTPUT:

#include <cstdio>
#include <queue>
#include <vector>
#include <cassert>
using namespace std;

#define NMAX 100000
#define MMAX 50000

// entry i is the list of edges implied
// by observation i
vector<pair<int, int>> edges[MMAX];

// For each cow, list of successors of that cow
// in the graph constructed from some set of the
// observations.
vector<int> succ[NMAX];

// For each cow, the number of precessors
// in the graph.
int pred[NMAX];

// Resulting lexicographically earliest topological sort.
int result[NMAX];

// Check if topological sort is doable, for the first
// k observations, and if so, put the answer
// in the `result` array.
bool doable(int n, int k) {
  // Setup the graph from the first k observations.
  for (int i = 0; i < n; i++) {
    succ[i].clear();
    pred[i] = 0;
  }
  for (int i = 0; i < k; i++) {
    for (auto p : edges[i]) {
      succ[p.first].push_back(p.second);
      pred[p.second]++;
    }
  }

  // Initialize the queue with cows that can be first.
  priority_queue<int> q;
  for (int i = 0; i < n; i++) {
    if (pred[i] == 0) {
      // Use the negative of the ID because we want
      // to get the min when we pop, but priority_queue
      // returns the max.
      q.push(-i);
    }
  }

  for (int i = 0; i < n; i++) {
    if (q.empty()) {
      // Nothing in queue - topological sort is impossible.
      return false;
    }
    int v = -q.top();
    q.pop();

    result[i] = v;
    for (int next : succ[v]) {
      pred[next]--;
      if (pred[next] == 0) {
        q.push(-next);
      }
    }
  }

  return true;
}

int main() {
  int n, m;
  scanf("%d", &n);
  scanf("%d", &m);
  assert(1 <= m && m <= MMAX);
  assert(1 <= n && n <= NMAX);

  for (int i = 0; i < m; i++) {
    int d;
    scanf("%d", &d);
    int last;
    for (int j = 0; j < d; j++) {
      int e;
      scanf("%d", &e);
      e--;
      if (j > 0) {
        edges[i].push_back(make_pair(last, e));
      }
      last = e;
    }
  }

  // Binary search
  // Invariant: lo <= ans < hi
  int lo = 0;
  int hi = m+1;
  while (hi > lo+1) {
    int mid = (lo + hi) / 2;
    if (doable(n, mid)) {
      lo = mid;
    } else {
      hi = mid;
    }
  }

  int ans = lo;

  // Run this again, to get the answer
  // into the `result` array.
  doable(n, ans);

  for (int i = 0; i < n; i++) {
    printf("%d%c", result[i] + 1, i == n-1 ? '\n' : ' ');
  }
}

Farmer John is bringing his N� cows, conveniently numbered 1…N1…�, to the county fair, to compete in the annual bovine talent show! His i�th cow has a weight wi�� and talent level ti��, both integers.

Upon arrival, Farmer John is quite surprised by the new rules for this year's talent show:

(i) A group of cows of total weight at least W� must be entered into the show (in order to ensure strong teams of cows are competing, not just strong individuals), and

(ii) The group with the largest ratio of total talent to total weight shall win.

FJ observes that all of his cows together have weight at least W�, so he should be able to enter a team satisfying (i). Help him determine the optimal ratio of talent to weight he can achieve for any such team.

INPUT FORMAT (file talent.in):

The first line of input contains N� (1≤N≤2501≤�≤250) and W� (1≤W≤10001≤�≤1000). The next N� lines each describe a cow using two integers wi�� (1≤wi≤1061≤��≤106) and ti�� (1≤ti≤1031≤��≤103).

OUTPUT FORMAT (file talent.out):

Please determine the largest possible ratio of total talent over total weight Farmer John can achieve using a group of cows of total weight at least W�. If your answer is A�, please print out the floor of 1000A1000� in order to keep the output integer-valued (the floor operation discards any fractional part by rounding down to an integer, if the number in question is not already an integer).

SAMPLE INPUT:

3 15
20 21
10 11
30 31

SAMPLE OUTPUT:

1066

In this example, the best talent-to-weight ratio overall would be to use just the single cow with talent 11 and weight 10, but since we need at least 15 units of weight, the optimal solution ends up being to use this cow plus the cow with talent 21 and weight 20. This gives a talent-to-weight ratio of (11+21)/(10+20) = 32/30 = 1.0666666..., which when multiplied by 1000 and floored gives 1066.

Farmer John要带着他的N�头奶牛,方便起见编号为1…N1…�,到农业展览会上去,参加每年的达牛秀!他的第i�头奶牛重量为wi��,才艺水平为ti��,两者都是整数。

在到达时,Farmer John就被今年达牛秀的新规则吓到了:

(一)参加比赛的一组奶牛必须总重量至少为W�(这是为了确保是强大的队伍在比赛,而不仅是强大的某头奶牛),并且

(二)总才艺值与总重量的比

#include <cstdio>
#include <algorithm>
#include <cassert>
using namespace std;

#define NMAX 250
#define WMAX 1000

#define infinite 1000000000000000000LL

// The inputs
int weights[NMAX];
int talent[NMAX];

int n;
int w;

// The dp state.
// For 0 <= i < w, this is the maximum adjusted-talent-score achievable
// with weight exactly i.
// For i=w, this is the maximum talent achievable
// with weight AT LEAST w.
long long dp[WMAX + 1];

// Check if a ratio of y/1000 is achievable.
bool doable(int y) {
  for (int i = 0; i <= w; i++) {
    dp[i] = -infinite;
  }
  dp[0] = 0;

  for (int j = 0; j < n; j++) {
    long long value = 1000*(long long)talent[j] - y*(long long)weights[j];
    int inc = weights[j];
    for (int k = w; k >= 0; k--) {
      int k1 = min(w, k + inc);
      if (dp[k] != -infinite) {
        if (dp[k1] < dp[k] + value) {
          dp[k1] = dp[k] + value;
        }
      }
    }
  }

  return dp[w] >= 0;
}

int main() {
  scanf("%d", &n);
  scanf("%d", &w);
  assert(1 <= n && n <= NMAX);
  assert(1 <= w && w <= WMAX);

  for (int i = 0; i < n; i++) {
    scanf("%d", &weights[i]);
    scanf("%d", &talent[i]);
    assert(1 <= weights[i] && weights[i] <= 1000000);
    assert(1 <= talent[i] && talent[i] <= 1000);
  }

  // Binary search
  // Invariant: lo <= answer < hi
  int lo = 0;
  int hi = (1000 * 250 * 1000) + 1;
  while (hi > lo + 1) {
    int mid = (lo + hi) / 2;
    if (doable(mid)) {
      lo = mid;
    } else {
      hi = mid;
    }
  }
  printf("%d\n", lo);
}

猜你喜欢

转载自blog.csdn.net/GeekAlice/article/details/129338876
今日推荐