Codeforces Beta Round #90 C: Education Reform
問題概要
長さM(<50)の配列A, B, C(A[i]
考えたこと
- B[i] - A[i] <= 100がどう見ても怪しい。
- Cが単調増加ということは最初にCでソートしておけばOK。
- 復元は直前の状態を覚えておけばよいから、総和を値としたDPか。
- 最小必要な状態は(いくつ目、何番目に選んだか、今のXの値)。もちろん今のXの値はa[i]からの差分で覚えておく。
- 今にして思えばmapでよかったような気もするが、map使ってTLEしていた人もいたので微妙。
- で、後ろの方全部に配る。状態数がO(M*N*DIFF)で遷移にO(M)なので全体としてはO(N*DIFF*M^2)。いちおう間に合いそう。
- というか本当に何の工夫もない問題だなあ。
- あとはひたすらガリガリ書く。
- 長さNのDPって、0番目に番兵っぽいのを置いてdp[N]みたいなのを最後の値にするのが大抵綺麗なんだけど、今回は基底の設定が面倒なのでdp[N-1]が最終的な答えとなって自分の中の美意識に反する。
- 無事通ってた。unratedでみんなやる気が無かったとはいえ20位という自分にしてはよくできた結果だった。
本番で通ったコード
#include <iostream> #include <vector> #include <cstdio> #include <algorithm> using namespace std; typedef long long int64; const int MAX_M = 100; const int MAX_DIFF = 100; int N, M, K; int64 as[MAX_M], bs[MAX_M]; int cs[MAX_M]; int64 dp[MAX_M][MAX_M][MAX_DIFF + 1]; //(幾つ目、何教科目、a[i] + いくつ) bool visited[MAX_M][MAX_M][MAX_DIFF + 1]; pair<int,int> prev[MAX_M][MAX_M][MAX_DIFF + 1]; //(何教科目、a[prev] + いくつ) struct subject{ int64 a, b, c, orig; }; subject subs[MAX_M]; bool operator<(const subject& lhs, const subject& rhs){ return lhs.c < rhs.c; } void solve(){ for(int i=0; i<M; i++){ for(int j=0; j<=subs[i].b - subs[i].a; j++){ dp[i][0][j] = subs[i].a + j; visited[i][0][j] = true; } } for(int i=0; i<M-1; i++){ for(int j=0; j<N-1; j++){ for(int k=0; k<=subs[i].b - subs[i].a; k++)if(visited[i][j][k]){ int64 cur = subs[i].a + k; int64 add_next = cur + K; int64 multy_next = cur * K; for(int l=i+1; l<M; l++)if(subs[i].c < subs[l].c){ //加算 if(subs[l].a <= add_next && add_next <= subs[l].b){ if( (!visited[l][j+1][add_next - subs[l].a]) || dp[l][j+1][add_next - subs[l].a] < add_next + dp[i][j][k]){ dp[l][j+1][add_next - subs[l].a] = add_next + dp[i][j][k]; visited[l][j+1][add_next - subs[l].a] = true; prev[l][j+1][add_next - subs[l].a] = make_pair(i, k); } } //積算 if(subs[l].a <= multy_next && multy_next <= subs[l].b){ if( (!visited[l][j+1][multy_next - subs[l].a]) || dp[l][j+1][multy_next - subs[l].a] < multy_next + dp[i][j][k]){ dp[l][j+1][multy_next - subs[l].a] = multy_next + dp[i][j][k]; visited[l][j+1][multy_next - subs[l].a] = true; prev[l][j+1][multy_next - subs[l].a] = make_pair(i, k); } } } } } } int64 best = -1; int key_id = -1, key_diff = -1; for(int i=0; i<M; i++){ for(int j=0; j<=MAX_DIFF; j++)if(visited[i][N-1][j]){ if(best < dp[i][N-1][j]){ best = dp[i][N-1][j]; key_id = i; key_diff = j; } } } if(best == -1){ puts("NO"); return ; } puts("YES"); vector<pair<int,int64> > path; for(int i=N-1; i>=0; i--){ pair<int,int> cur = prev[key_id][i][key_diff]; path.push_back( make_pair(subs[key_id].orig, subs[key_id].a + key_diff) ); key_id = cur.first; key_diff = cur.second; } for(int i=N-1; i>=0; i--){ cout << path[i].first << " " << path[i].second << endl; } } int main(){ cin >> N >> M >> K; for(int i=0; i<M; i++){ cin >> as[i] >> bs[i] >> cs[i]; subs[i] = (subject){as[i], bs[i], cs[i], i+1}; } sort(subs, subs+M); solve(); return 0; }