cafelier のSRM参加記録です。コンテスト中に考えてたことを執拗に全部書き残すとどうなるだろうかという試み本番中にこういうコードが書きたかったなあ、という後で書いた反省コードを書き残す試み
スパムが来たのでしばらくコメント欄をはてなユーザ限定にしています、すみません、
あとで | |
DPテンプレート改を投入
typedef long long LL; template<typename T> struct DP3x { int N1, N2, N3; vector<T> data; DP3x(int, int N2, int N3, const T& t = T()) : N1(2), N2(N2), N3(N3), data(N1*N2*N3, t) { assert(data.size()*sizeof(T) < (1<<26)); } T& operator()(int i1, int i2, int i3) { i1&=1; return data[ ((i1*N2)+i2)*N3+i3 ]; } void swap(DP3x& rhs) { data.swap(rhs.data); } }; static const LL inf = (1LL << 60); class RoadOrFlightHard { public: long long minTime(int N, int roadFirst, int roadProd, int roadAdd, int roadMod, int flightFirst, int flightProd, int flightAdd, int flightMod, int K) { vector<LL> rt(N), ft(N); { rt[0] = roadFirst % roadMod; for(int i=1; i<N; ++i) rt[i] = (rt[i-1]*roadProd + roadAdd) % roadMod; ft[0] = flightFirst % flightMod; for(int i=1; i<N; ++i) ft[i] = (ft[i-1]*flightProd + flightAdd) % flightMod; } DP3x<LL> dp(N+1, K+1, 2); for(int n=0; n<=N; ++n) for(int k=0; k<=K; ++k) if( n == 0 ) { dp(n,k,0) = 0; dp(n,k,1) = inf; // ※追記:この行抜けてた。酷い。MLE以前の問題だ… } else { dp(n,k,0) = min(dp(n-1,k,0), dp(n-1,k,1)) + rt[n-1]; if( k == 0 ) dp(n,k,1) = inf; else dp(n,k,1) = min(dp(n-1,k,1), dp(n-1,k-1,0)) + ft[n-1]; } LL ans = inf; for(int k=0; k<=K; ++k) ans = min(ans, min(dp(N,k,0), dp(N,k,1))); return ans; } };
presented by cafelier/k.inaba under
cafelier2010/04/21 09:47証明こんな面倒くさくする必要なかったなー
・点被覆(=どの辺もどっちかの頂点はカバーされてる)の補集合は独立点集合(=どの辺もどっちかの頂点はカバーされてない)
・独立点集合の補集合は点被覆
・よって、 最小点被覆←補集合→最大独立点集合
・二部グラフの場合は、|最小点被覆| = |最大マッチング|
・よって二部グラフの場合は、|最大独立点集合|=|V|-|最大マッチング|