こちらは最近の練習のおかげで解けるようになった問題。
http://wupc2nd.contest.atcoder.jp/tasks/wupc_08
Autumn Festの問Hと似た問題。
まず、列車の数が高々200で、始点終点で合わせて400個の駅だけ考慮すればいいので、座標圧縮で余計な駅を削除する。
次に、列車ごとに始点の駅が西(数字の小さい方)から並ぶようにして、DPすればよい。
DPは、2本以上列車が止まる駅の東端と1列車が止まる駅の東端の2つを要素に持ち、そのような列車運行を行うパターンを値に持つ2次元配列で行う。
ある駅が区間S~Tを運行する場合、S-1以降に2本以上列車が止まる上記配列に対し、以下のようにDPする。
たとえばXまで2本、Yまで1本列車が止まるパターンに対し:
- T<=X以下の場合、すでにTまでの駅は2本以上列車が止まるので、今見ている列車は通っても通らなくてもよい。よってパターン数を2倍にする
- X<T<=Yの場合、つまりTが1本だけ列車が止まる駅の場合、Tまで2本止まる配列要素に今の値を加算する
- Y<T、つまりTが1本も列車が止まらない駅の場合、Yまで2本、Tまで1本止まる配列要素に今の値を加算する。
最終的には、東端の駅に2本以上列車が止まるパターン数を回答すればよい。
計算量はO(駅数^3)なので駅が200程度なら問題なし。
int N,M; int TS[201]; int TT[201]; int rm[100001]; vector<int> rmv; vector<pair<int,int> > TR; ll num[1000][1000]; // num[y][x] xまで2個以上、yまで1個 void solve() { int x,y,i,j,rr,TM,nc; int tx,ty,ng,LS; char cmd[100]; ll p,cch; N=GETi(); M=GETi(); ng=0; rmv.clear(); ZERO(rm); FOR(i,M) { TS[i]=GETi(); TT[i]=GETi(); if(TS[i]==1) ng |= 1; if(TT[i]==N) ng |= 2; rmv.push_back(TS[i]); rmv.push_back(TT[i]); } sort(rmv.begin(),rmv.end()); if(ng!=3) { _P("0\n"); return; } sort(rmv.begin(),rmv.end()); rmv.erase(unique(rmv.begin(), rmv.end()), rmv.end()); FOR(i,rmv.size()) { if(i==0) rm[rmv[0]]=1; else if(rmv[i]==rmv[i-1]+1) rm[rmv[i]]=rm[rmv[i-1]]+1; else rm[rmv[i]]=rm[rmv[i-1]]+2; LS=rm[rmv[i]]; } TR.clear(); FOR(i,M) TR.push_back(make_pair(rm[TS[i]],rm[TT[i]])); sort(TR.begin(),TR.end()); ZERO(num); num[0][0]=1; FOR(i,TR.size()) { int s = TR[i].first; int t = TR[i].second; for(y=LS;y>=s-1;y--) { for(x=LS;x>=y;x--) { if(!num[y][x]) continue; if(t<=y) { num[y][x] +=num[y][x]; num[y][x] %= 1000000007; } else if(t<=x) { num[t][x] +=num[y][x]; num[t][x] %= 1000000007; } else { num[x][t] +=num[y][x]; num[x][t] %= 1000000007; } } } } _P("%lld\n",num[LS][LS]%1000000007); return; }
まとめ
例題の一番下にあるけど、必ずしも駅間で列車が通らない区間があってもいいのね。
これを正しく処理できなくて何度かWAしてしまった。