2009-11-26
SRM453.5 Div1 Easy: MazeMaker
|- 高々2500ノードで、各ノードからのarcは高々50本
- ということで、dijkstraで解く方法
#define sz(a) int((a).size()) #define pb push_back #define all(c) (c).begin(),(c).end() #define tr(c,i) for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); i++) #define rep(var,n) for(int var=0;var<(n);var++) #define found(s,e) ((s).find(e)!=(s).end()) class MazeMaker { public: int longestPath(vector <string> maze, int startRow, int startCol, vector <int> moveRow, vector <int> moveCol) { int N=sz(maze), M=sz(maze[0]), NM=N*M, Z=sz(moveRow); vector<bool> ok(NM,false); rep(r,N)rep(c,M) if(maze[r][c]=='.') ok[M*r + c] = true; vector<vector<int> > ar(NM,vector<int>(NM,infty)); int start = M*startRow + startCol; rep(ri,N)rep(ci,M){ int i = M*ri + ci; if (!ok[i]) continue; rep(z,Z){ int rj=ri+moveRow[z], cj=ci+moveCol[z]; if(0<=rj && rj<N && 0<=cj && cj<M){ int j = M*rj + cj; ar[i][j]=1; } } } pair<vector<int>,vector<int> > res = dijkstra_all(ar, start); vector<int> distances = res.first; int dmax=0; rep(i,NM){ if (i==start || !ok[i]) continue; int d=distances[i]; if (d==infty) return -1; if (d>dmax) dmax=d; } return dmax; } };
- dijkstraはスタート地点から他の全ノードへの距離を求めるやつ
- predecessor返してるけど使わない(ので消してもいい)
const int infty = INT_MAX; template <typename T> T infsum(T a, T b){ return (a == infty || b == infty)? infty : (a + b); } template <typename T> pair<vector<T>,vector<int> > dijkstra_all(const vector<vector<T> >& arclength, int start_v) { int N = arclength.size(); set<int> S; vector<T> distance(N, infty); // inftyは適当な大きな数 vector<int> predecessor(N, -1); S.insert(start_v); distance[start_v] = 0; rep(v,N){ if (v == start_v) continue; if (arclength[start_v][v] == infty) continue; distance[v] = arclength[start_v][v]; predecessor[v] = start_v; } while (S.size() < N) { // 各点へ // find v* from V¥S with distance(v*) = min{distance(v):v from V¥S} int v_ = -1; T d_ = infty; rep(v,N){ if (found(S,v)) continue; if (distance[v] < d_) { d_ = distance[v]; v_ = v; } } if (v_==-1) break; S.insert(v_); rep(v,N){ // FOR ALL v from V¥S DO if (found(S,v)) continue; T d_ = infsum(distance[v_], arclength[v_][v]); if (d_ < distance[v]) { distance[v] = d_; predecessor[v] = v_; } } } return make_pair(distance,predecessor); }
SRM453.5
|11.25.2009+
.5って何さ
DIV | level | 問題名 | 競技中 | 後で | System Test | 通過率 | 備考 |
---|---|---|---|---|---|---|---|
1 | 250 | MazeMaker | o | - | failed | 0 | |
1 | 450 | PlanarGraphShop | 撃墜された | - | - | - | |
1 | 1000 | TheAlmostLuckyNumbers | 間に合わず | - |
250点: MazeMaker
- 撃墜は免れたがfailed system test...
- TLE
- 教訓。
- 幅優先なところでpriority_queueとか書いてるとはまる
- ダイクストラで解ける?と思って後で書いたら速かった。
- 以下、投稿した恥コード:
- carとかcadrとかマクロあると非常に便利
#define sz(a) int((a).size()) #define pb push_back #define all(c) (c).begin(),(c).end() #define tr(c,i) for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); i++) #define rep(var,n) for(int var=0;var<(n);var++) #define found(s,e) ((s).find(e)!=(s).end()) typedef pair<int,int> i_i; typedef pair<int,pair<int,int> > i_ii; #define cons(x,y) make_pair((x),(y)) #define car(x) ((x).first) #define cdr(x) ((x).second) #define cadr(x) (x).second.first #define cddr(x) (x).second.second class MazeMaker { public: int longestPath(vector <string> maze, int startRow, int startCol, vector <int> moveRow, vector <int> moveCol) { int N=sz(maze), M=sz(maze[0]), NM=0, Z=sz(moveRow); rep(r,N)rep(c,M) if(maze[r][c]=='.')NM++; priority_queue<i_ii> pq; vector<vector<int> > vd(N,vector<int>(M,INT_MAX)); int vdc=0; pq.push(cons(0,cons(startRow,startCol))); while(!pq.empty()){ i_ii t = pq.top(); pq.pop(); int i=-car(t), r=cadr(t), c=cddr(t); if (maze[r][c]=='X') continue; if (vd[r][c]<i) continue; if (vd[r][c]==INT_MAX) vdc++; vd[r][c]=i; if (vdc == NM) break; rep(z,Z){ int r2 = r + moveRow[z]; if (r2 < 0 || N <= r2) continue; int c2 = c + moveCol[z]; if (c2 < 0 || M <= c2) continue; pq.push(cons(-(i+1),cons(r2,c2))); } } if (vdc < NM) return -1; int mx=0; rep(r,N)rep(c,M) { if (vd[r][c]==INT_MAX) continue; if (vd[r][c]>mx)mx=vd[r][c]; } return mx<INT_MAX ? mx : -31; } };
- 後で書いた、ちゃんと通るコードは別エントリにて
450点: PlanarGraphShop
- 投稿コード:
#define sz(a) int((a).size()) #define pb push_back #define all(c) (c).begin(),(c).end() #define tr(c,i) for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); i++) #define rep(var,n) for(int var=0;var<(n);var++) #define FOR(var,from,to) for(int var=(from);var<=(to);var++) #define RFOR(var,from,to) for(int var=(to);var>=(from);var--) #define found(s,e) ((s).find(e)!=(s).end()) class PlanarGraphShop { vector<int> xs; int xsn; vector<int> m,m0; int cost(int v, int e){ return v*v*v + e*e; } int sub(int n){ if(m[n]<INT_MAX) return m[n]; priority_queue<int> pq; tr(m0,it){ int x=*it; if(x>n) continue; if(x==n)return 1; pq.push(-(1+m[n-x])); } return -pq.top(); } public: int bestCount(int N) { double r = pow((double)N, 1.0/3); int rc = (int)floor(r + .00001); set<int> cs; FOR(n,1,rc){ FOR(e,0,max(0,n*2-3)){ int c=cost(n,e); if(c>N) continue; if(c==N) return 1; cs.insert(c); } } xs.assign(all(cs)); xsn=sz(xs); m0.clear(); m.resize(N+1); FOR(i,0,N) m[i]=INT_MAX; tr(xs,it) { m0.pb(*it); m[*it]=1; } FOR(i,1,N){ if (m[i] < INT_MAX) continue; m[i] = sub(i); } return m[N]; } };
- 撃墜される
- はい。n*2-3て何ですか
- 教訓:planar graphとかぐぐればよかったのに(wikipediaに載ってる!!!)
- n*2-3 を n>=3でn*3-6 にするだけで通った
1000点: TheAlmostLuckyNumbers
- そんなに難しい問題にも見えない(けど時間ない)
- 時間ないとか書いてるけど、途中まではコード書いたんだからね
- て3問目までコード書いてたの初めてかも
- 4,7,44,47,74,77,...という数列
- これらの倍数の数を数えればいい
- Inclusion-exclusion principle
- 44とか4の倍数だから捨ててもいいっしょ
- とかその辺りまで
class TheAlmostLuckyNumbers { vector<ll> lns; int lnsn; int keta(ll x){ if(x<10) return 1; return 1+keta(x/10); } ll rp(int k,int mask){ ll r=0, b=1LL; for(int i=0,m=1;i<k;i++,m<<=1){ r += b * ((mask&m)? 7 : 4); b *= 10LL; } return r; } ll sub(ll x){ if(x==0) return 0; int k=keta(x); ll cx=0; rep(i,lnsn){ cx += x / lns[i]; } printf("sub(%lld:%d) <= %lld\n", x,k, cx); return cx; } public: long long count(long long a, long long b) { lns.clear(); for(int k=1;k<=10;k++){ for(int m=0;m<1<<k;m++){ ll r = rp(k,m); if (r>b) break; int skip=0; rep(i,sz(lns)) if (r%lns[i]==0) skip=1; if(!skip) lns.pb(r); } } lnsn = sz(lns); cout << lnsn << " " << lns << endl; ll x=1LL; int f=lnsn; rep(i,lnsn){ x *= lns[i]; if(x>b){ f=i; break; } } printf("s1.size = %d\n", lnsn); // ... この辺りまで return sub(b) - sub(a-1); } };
- きなばさんが投稿に3秒足りなかったらしい
Challenge Phase
- 450点轟沈
System Test
- 250点Failed System Test
- 毎度ながら赤い字がどきっとする
0点...
1518→1359 (-159) 派手に落ちたなー