USACO 2020 December Contest, Platinum Problem 1. Sleeping Cows

Правка en1, от gmyu.michael, 2020-12-27 06:12:10

[to record the solution for my own record for easy understanding]

Problem statement: http://usaco.org/index.php?page=viewproblem2&cpid=1068

dp[i, j, k] where - i-th barn, where the corresponding cows that fits is match[i] - out of match[i] cows, j of them are assigned to barn i+1 ... N - and flag = 0 means no mis-match cows / all cows are in barns, 1 = allow some cows to left behind

so, each time we add a new barn (barn and cow are sorted low to high), we have additional match[i] — match[i-1] cow to assign. Let's take j from dp[i-1] and k from those now cows dp[i, j+k, f] += dp[i, j, f] * (probability of picking k out of match[i] — match[i-1], which is a simple c(n,m) )

note that barn i is the largest, so it must be occupied unless all cows are assigned (i.e. f = 0). So, in above case - if we pick j from dp[i-1], and one of them landed at barn i, it is good, but the number of cow after barn i+1 is actually j+k-1 - if it does not land at barn i, for the k cow we picked, one of them must be used for barn i. And again then, the correct index should be j+k-1. So, after the above dp, before we finish barn i, we need to do j+1 -> j index shift for f = 1. Note that we can pick any of (j+1) cow to fit at barn i, so times (j+1).

if f=0, all the cows are assigned so that we can leave barn i open (not used). So, we need the original count (not assign to barn i) and add the j+1 -> j shift

code as below

/*
ID: USACO_template
LANG: C++
PROG: http://usaco.org/index.php?page=viewproblem2&cpid=1068
*/
#include <iostream>  //cin , cout
#include <fstream>   //fin, fout
#include <stdio.h>   // scanf , pringf
#include <cstdio>
#include <algorithm> // sort , stuff
#include <stack>     // stacks
#include <queue>     // queues
#include <map>
#include <string>

using namespace std;

typedef pair<int, int>          pii;
typedef vector<int>             vi;     /// adjlist without weight
typedef vector<pii>             vii;    /// adjlist with weight
typedef vector<pair<int,pii>>   vpip;   /// edge with weight
typedef long long               ll;

#define mp  make_pair
#define fst first
#define snd second
#define pb  push_back
#define sz(x) (int)(x).size()
#define trav(u, adj_v) for (auto& u: adj_v)

const int MOD = 1e9+7;  // 998244353;
const int MX  = 2e5+5;   //
const ll  INF = 1e18;    //

#define MAXV 3007
#define MAXE 100007

bool debug = false, submit = true;

int N;
int s[MAXV], t[MAXV];

int match[MAXV];
ll dp[MAXV][MAXV][2];
ll c[MAXV][MAXV];

int main() {
    debug = true;
    ios_base::sync_with_stdio(0); cin.tie(0);

    int i, j, k;

    cin >> N ;
    for(i=1;i<=N;i++) cin >> s[i];
    for(i=1;i<=N;i++) cin >> t[i];
    sort(s+1, s+1+N); sort(t+1, t+1+N);

    /// match[j] means the j-th barn can be house upto match[j]-th cow (after the small to large sort is completed
    i=1; j = 1;
    while(i<=N && j<=N) {
        match[j] = match[j-1];
        while(i<=N && t[j] >= s[i]) {
            match[j] = i; i++;
        }
        j++;
    }
    while(i>=N && j<=N) { match[j] = match[j-1]; j++;}

    /// pre caculate probability of pick m from n, C(n, m), which = c(n-1, m) + c(n-1, m-1)
    c[0][0] = 1LL;
    for(i=1; i<=N; i++) {
        for(j=0; j<=N; j++) {
            c[i][j] = c[i-1][j] + ( (j-1>=0) ? c[i-1][j-1] : 0 );
            c[i][j] %= MOD;
        }
    }

    /// dp(i, j, f) is use upto i-th barn, and from 1 ... match[i] cow, at least j cows are assigned to bar i+1  ... N,
    /// f=0 is all cows are used, f=1 is not all cows are used
    dp[0][0][0] = 1LL;
    for(i=1; i<=N; i++) {
        /// for new barn i, let's pick k of cow between match[i-1] .. match[i] is not sitting in a barn, meaning barn i is not used
        /// but since barn i is the largest at this moment, it must be used unless all barns are assigned.
        /// if dp(i-1, j, f) occupies barn i, it is fine but that should go to dp(i, j+k-1, f) case instead of j+k case. I.e. make correction of j+1 --> j
        /// if not occupies barn i, it is fine, but barn i should also be occupied by one of the k cow picked. I.e. also j+1 -> j shift.
        /// so for flag = 1, we need to shift j+1 --> j
        /// for the case of flag = 0, it means that all cows are assigned
        /// same as above, we need to do the j+1 -> j shift. But since all cows are assigned, we can left barn i open, i.e. original case also counts
        for(j=0; j<=match[i-1]; j++) {
            for(int f=0; f<=1; f++) {
                int klen = match[i] - match[i-1];
                for(k=0; k <= klen; k++) {
                    int nf = 1;
                    if(f==0 && k == klen) nf = 0; /// all cows used
                    dp[i][j+k][nf] += (dp[i-1][j][f] * c[klen][k])%MOD;   /// from klen pick k, neither of those cow would fit barn (i-1)
                    dp[i][j+k][nf] %= MOD;
                }
            }
        }
        /// then we can not let j cow sit at barn i, but barn i must be used unless it is all assigned.
        /// let's assing barn i to a cow, meaning we pretend to pick (j+1) cow not to match, and pick one out of (j+1) to fit barn i
        for(j=0; j<match[i];j++) {
            dp[i][j][0] += ( dp[i][j+1][0] * (ll)(j+1) )%MOD; dp[i][j][0] %=MOD;
            dp[i][j][1] = ( dp[i][j+1][1] * (ll)(j+1) )%MOD; dp[i][j][1] %=MOD;     ///
        }
        dp[i][match[i]][1] = 0LL;
    }

    cout << (dp[N][0][0]%MOD + dp[N][0][1]%MOD) % MOD << endl;

}
Теги usaco

История

 
 
 
 
Правки
 
 
  Rev. Язык Кто Когда Δ Комментарий
en5 Английский gmyu.michael 2020-12-28 23:42:56 41 Tiny change: ' shift\n\n<spoil' -> ' shift\n\n\n<spoil'
en4 Английский gmyu.michael 2020-12-28 04:36:13 6 Tiny change: ' solution for my own record for easy ' -> ' solution **for my own record** for easy '
en3 Английский gmyu.michael 2020-12-27 06:21:51 7
en2 Английский gmyu.michael 2020-12-27 06:19:20 1052 (published)
en1 Английский gmyu.michael 2020-12-27 06:12:10 5640 Initial revision (saved to drafts)