2014年12月28日日曜日

JOI春合宿2014 Day1-1 Bus

解法

よくわからない。
最初に乗る辺(バス停 1 から生えてるやつ) を決めて、それぞれの最短到着時刻をダイクストラで求める。
普通にやると遅くなるのは自明なので、あらかじめ辺を遅い順にソートしておくと、嬉しくなる(日本語難しいからソースコード(ry )。前の辺に乗った時よりも到着時刻が早くなっていれば、そのときの到着時刻と出発時刻をデキューに突っ込む。早くなってなければ、そのバスに乗っても意味がなさそうだから無かったことにする。
各クエリに答える時間はにぶたんでいい感じに求まる。
オーダーよくわかんない。

ソース

#include<bits/stdc++.h>  
using namespace std;
const int INF = 1 << 30;
 
struct Edge{
  int to, st, gr;
  bool operator<(const Edge& e)const{
    return st < e.st || (st == e.st && gr < e.gr);
  }
};
typedef vector< vector< Edge > > Graph;
typedef pair< int , int > Pi;
 
Graph info;
vector< int > min_time;
 
int Dijkstra(int idx){
  priority_queue< Pi, vector< Pi >, greater< Pi > > que;
  que.push( Pi( info[0][idx].gr, info[0][idx].to));
  min_time[0] = info[0][idx].st;
  while(!que.empty()){
    Pi p = que.top(); que.pop();
    if(p.second + 1 == info.size()) return p.first;
    if(p.first > min_time[p.second]) continue;
    for(int i = 0; i < info[p.second].size(); ++i){
      Edge& e = info[p.second][i];
      if(e.st < p.first) break; //バスの出発時刻のほうが早い
      if(min_time[e.to] <= e.gr) continue;
      min_time[e.to] = e.gr;
      que.push( Pi( e.gr, e.to));
    }
  }
  return -1;
}
 
 
int main(){
 
  //A: 出発バス停, B: 到着バス停, X: 出発時刻, Y: 到着時刻
 
  int N, M;
  int A, B, X, Y;
  int Q, L;
 
  scanf("%d %d", &N, &M);
  info.resize(N);
  min_time.resize(N, INF);
 
  for(int i = 0; i < M; ++i){
    scanf("%d %d %d %d", &A, &B, &X, &Y);
    --A, --B;
    info[A].push_back( (Edge){ B, X, Y});
  }
 
  for(int i = 0; i < N; ++i){
    sort(info[i].rbegin(), info[i].rend());
  }
 
  deque< Pi > good;
  
  int prev = INF;
  for(int i = 0; i < info[0].size(); ++i){
    int accept = Dijkstra(i); //Pi(到着時刻, 出発時刻)
    if(accept == -1) continue;
    else if(prev > accept){
      prev = accept;
      good.push_front( make_pair(prev, info[0][i].st));
    }
  }
  good.push_front( make_pair( -1, -1));
 
 
  scanf("%d", &Q);
  while(Q--){
    scanf("%d", &L);
    deque< Pi >::iterator it = lower_bound( good.begin(), good.end(), make_pair( L + 1, -INF));
    --it; //到着時刻直近で出発時刻が小さいもの
    printf("%d\n", it -> second);
  }
}

2014年12月14日日曜日

JOI2015予選参加記

精神状態があまりよろしいものではなかった
5完+部分点20でした
追記:予選通過,本戦出場者各位よろしくね
  • 団体受験なので、家を出て学校の部室へ向かう
  • 無事学校に到着
  • 僕のバッグが廊下の壁に掲示してあるポスターを2分して、1つは「落ち」る。
  • 予選「落ち」というフラグを回収したかと絶望
  • 実はこれは、二分探索あるいは半分全列挙だったことを疑う
  • 知らない
  • だいぶ緊張している
  • 10分前くらいだったけど、よくわからない格ゲーを友達とやる
  • 2連敗
  • 1時間で3完してればいいか位の目処をたてる
  • はじまった
  • とりあえず1分くらいで6問分流し読み
  • 4問目簡単そう、文字なマップ系が2問あって強そうくらいな感想を得る
  • 1問目むずかしい
  • 冒頭の通り緊張のせいで精神状態がよくなくて、うまくソースを書けない
  • 思いついたことをそもままアウトプットしたソースがこちら
  • #include<bits/stdc++.h>
    using namespace std;
     
    template<typename T1, typename T2> istream& operator>>(istream& is, pair<T1,T2>& a){ return is >> a.first >> a.second; }
    template<typename T1, typename T2> ostream& operator<<(ostream& os, pair<T1,T2>& a){ return os << a.first << " "<<a.second; }
    template<typename T> istream& operator>>(istream& is, vector< T >& vc){ for(int i = 0; i < vc.size(); i++) is >> vc[i]; return is; }
    template<typename T> ostream& operator<<(ostream& os, vector< T >& vc){ for(int i = 0; i < vc.size(); i++) os << vc[i] << endl; return os; }
     
    #define ForEach(it,c) for(__typeof (c).begin() it = (c).begin(); it != (c).end(); it++)
    #define ALL(v) (v).begin(), (v).end()
    #define UNQ(s) { sort(ALL(s)); (s).erase( unique( ALL(s)), (s).end());}
    #define fr first
    #define sc second
     
    typedef pair< int , int > Pi;
    typedef pair< int , Pi > Pii;
     
    typedef long long int64;
    const int INF = 1 << 30;
    
    int main(){
      int A, B, C, D, P;
      cin >> A;
      cin >> B;
      cin >> C;
      cin >> D;
      cin >> P;
    
      int ret = 0;
      if(P <= C) ret = B;
      else{
        ret = B;
        ret += D * (P - C);
      }
      cout << min( A * P, ret) << endl;
    }
    
  • 世界一汚いソースコード
  • まあこんな問題でバグるはずがないということで、提出(13:05)
  • 2問目
  • 問題分がわかりにくそう
  • 読解力のない僕を駆逐しようとしている感
  • JOIくんがゲームを支配しているプロだと感じながら、適当に書く
  • サンプル通った
  • テンプレートに感謝、入出力が楽
  • これもバグるはずがないだろうということで、提出(13:15)
  • #include<bits/stdc++.h>
    using namespace std;
     
    template<typename T1, typename T2> istream& operator>>(istream& is, pair<T1,T2>& a){ return is >> a.first >> a.second; }
    template<typename T1, typename T2> ostream& operator<<(ostream& os, pair<T1,T2>& a){ return os << a.first << " "<<a.second; }
    template<typename T> istream& operator>>(istream& is, vector< T >& vc){ for(int i = 0; i < vc.size(); i++) is >> vc[i]; return is; }
    template<typename T> ostream& operator<<(ostream& os, vector< T >& vc){ for(int i = 0; i < vc.size(); i++) os << vc[i] << endl; return os; }
     
    #define ForEach(it,c) for(__typeof (c).begin() it = (c).begin(); it != (c).end(); it++)
    #define ALL(v) (v).begin(), (v).end()
    #define UNQ(s) { sort(ALL(s)); (s).erase( unique( ALL(s)), (s).end());}
    #define fr first
    #define sc second
     
    typedef pair< int , int > Pi;
    typedef pair< int , Pi > Pii;
     
    typedef long long int64;
    const int INF = 1 << 30;
    
    int main(){
      int N, M;
      cin >> N;
      cin >> M;
      vector< int > A(M);
      cin >> A;
    
      vector< vector< int > > B( M, vector< int >(N));
      cin >> B;
    
      vector< int > Point( N, 0);
      for(int i = 0; i < M; i++){
        int hazure = 0;
        for(int j = 0; j < N; j++){
          if(A[i] == B[i][j]){
            Point[j]++;
          } else {
            hazure++;
          }
        }
        Point[A[i] - 1] += hazure;
      }
      cout << Point;
    }
    
  • 3問目
  • 書いてみるととても簡単
  • 極めてやるだけ
  • 考えないといけない系を想定していたけどこれは驚いた
  • 書けた
  • 謎の値が出力される
  • 配列外参照に違いないと疑うも、配列外参照する要素がない
  • ここからintがいけない、long longだ!とかいう謎のデバッグを始める
  • 出力するとおかしくなってる気がするしこれはコンパイラが悪い
  • 変数の中身を丁寧に扱おうとする(以下ソースのgetの部分だね)
  • 何故かおかしくなくなった
  • gccからのハラスメント
  • 別におかしくなさそうなので提出(13:30)
  • #include<bits/stdc++.h>
    using namespace std;
     
    template<typename T1, typename T2> istream& operator>>(istream& is, pair<T1,T2>& a){ return is >> a.first >> a.second; }
    template<typename T1, typename T2> ostream& operator<<(ostream& os, pair<T1,T2>& a){ return os << a.first << " "<<a.second; }
    template<typename T> istream& operator>>(istream& is, vector< T >& vc){ for(int i = 0; i < vc.size(); i++) is >> vc[i]; return is; }
    template<typename T> ostream& operator<<(ostream& os, vector< T >& vc){ for(int i = 0; i < vc.size(); i++) os << vc[i] << endl; return os; }
     
    #define ForEach(it,c) for(__typeof (c).begin() it = (c).begin(); it != (c).end(); it++)
    #define ALL(v) (v).begin(), (v).end()
    #define UNQ(s) { sort(ALL(s)); (s).erase( unique( ALL(s)), (s).end());}
    #define fr first
    #define sc second
     
    typedef pair< int , int > Pi;
    typedef pair< int , Pi > Pii;
     
    typedef long long int64;
    const int INF = 1 << 28;
    
    
    int main(){
      int H, W;
      string mas[100];
      int num[150][150];
    
      cin >> H >> W;
      for(int i = 0; i < H; i++){
        cin >> mas[i];
      }
      for(int i = 0; i < H; i++){
        for(int j = 0; j < W; j++){
          num[i][j] = INF;
        }
      }
    
      for(int i = 0; i < H; i++){
        for(int j = 0; j < W; j++){
          if(mas[i][j] == 'c') num[i][j] = 0;
        }
      }
      for(int i = 0; i < H; i++){
        for(int j = 1; j < W; j++){
          num[i][j] = min( num[i][j], num[i][j - 1] + 1);
        }
      }
      for(int i = 0; i < H; i++){
        for(int j = 0; j < W; j++){
          if(j != 0) cout << " ";
          int get = num[i][j];
          if(get == INF) cout << -1;
          else cout << get;
        }
        cout << endl;
      }
    }
    
  • 流れが悪いながらも4問目
  • 何も考えずにDP書けそう
  • 実際にも書けた
  • 多分この問題のみが一発で書けたソースだと思う
  • 去年のbitDPとかなんだったんだろう
  • とか盛大にJOIを批評しつつも提出(13:47)
  • #include<bits/stdc++.h>
    using namespace std;
     
    template<typename T1, typename T2> istream& operator>>(istream& is, pair<T1,T2>& a){ return is >> a.first >> a.second; }
    template<typename T1, typename T2> ostream& operator<<(ostream& os, pair<T1,T2>& a){ return os << a.first << " "<<a.second; }
    template<typename T> istream& operator>>(istream& is, vector< T >& vc){ for(int i = 0; i < vc.size(); i++) is >> vc[i]; return is; }
    template<typename T> ostream& operator<<(ostream& os, vector< T >& vc){ for(int i = 0; i < vc.size(); i++) os << vc[i] << endl; return os; }
     
    #define ForEach(it,c) for(__typeof (c).begin() it = (c).begin(); it != (c).end(); it++)
    #define ALL(v) (v).begin(), (v).end()
    #define UNQ(s) { sort(ALL(s)); (s).erase( unique( ALL(s)), (s).end());}
    #define fr first
    #define sc second
     
    typedef pair< int , int > Pi;
    typedef pair< int , Pi > Pii;
     
    typedef long long int64;
    const int64 INF = 1LL << 58;
    
    int main(){
      int64 N, M;
      cin >> N >> M;
      vector< int64 > D(N);
      cin >> D;
      vector< int64 > C(M);
      cin >> C;
    
    
      // dp[i][j]: i日目に街jにいるときの疲労度の最小値
      vector< vector< int64 > > dp( M + 1, vector< int64 >( N + 1, INF));
      dp[0][0] = 0;
      for(int i = 0; i < M; i++){ //日数
        for(int j = 0; j < N; j++){ // 今いる街 0
          if(dp[i][j] == INF) continue;
          dp[i + 1][j] = min( dp[i + 1][j], dp[i][j]);
          dp[i + 1][j + 1] = min( dp[i + 1][j + 1], dp[i][j] + D[j] * C[i]);
        }
      }
      int64 ret = INF;
      for(int i = 0; i <= M; i++){
        ret = min( ret, dp[i][N]);
      }
      cout << ret << endl;
    }
    
  • 精神状態がよくなる
  • 顧問の先生と今年は多分、4完ボーダーより上だなあという話を入れる
  • 顧問の先生が4.5完がボーダーという読みが入る
  • とても焦る
  • 精神状態がよくなくなった
  • 5問目は実装ゲーっぽいので6問目を読む
  • うーん
  • 5問目を読む
  • うーん
  • どっちを解くべきか迷う
  • 部分点が生死を極めると信じて、とりやすそうな6問目を書く
  • 適当な末尾再帰
  • 全探だね
  • 適当すぎてバグったりしたけど、すぐ直った
  • 入力ケース1だけ通った(14:22)
  • 2を微妙に放置してみるもこれは天文的な時間がかかりそう
  • (ソースコード紛失しました)
  • 5問目を読む
  • 5問目どうやって早くするんだろう
  • 愚直な全探索を書く
  • サンプル1だけ通った(14:30くらい)
  • 2以降はやばそう
  • トイレに行く
  • 戻ってくる
  • 終わってない(諦め
  • (ここへんから理不尽なバグが続く)
  • JOI紋章と似た感じのやり方かなあという考察をする
  • 直近に'.'へと変化した数字の八方向以外は、盤面とは関係無いような気がする
  • そこの八方向だけみるようにする
  • 終わらない(謎)
  • 見るべき座標たちの数が指数関数的に増加してる
  • 見るべき座標はそこまで増加しないはずだろう!!とキレはじめる
  • コンパイラによるハラスメントを疑う
  • やめたい
  • よくわからなくてつらい
  • JOI予選落ち不可避
  • 適当にデバッグも改善傾向が見られない
  • やめよう
  • 顧問の先生の名前が浮かぶ
  • 関数の名前をそれにする
  • セグメント例外(絶望
  • 競プロ初心者にもなれなかった
  • よくわからないけど、プログラムの流れ的に起こりえないはずの条件文をたくさん加える
  • なぜか通った
  • 条件無視とかつらみ
  • 歓喜
  • 入力ケース2
  • 終わらないと思わせつつ、5秒位たって出力というプロな溜めが入る
  • 全部の入力ケースが通った
  • 時間がやばそうだけど、時間制限ない
  • 提出(15:11)
  • #include<bits/stdc++.h>
    using namespace std;
     
    template<typename T1, typename T2> istream& operator>>(istream& is, pair<T1,T2>& a){ return is >> a.first >> a.second; }
    template<typename T1, typename T2> ostream& operator<<(ostream& os, pair<T1,T2>& a){ return os << a.first << " "<<a.second; }
    template<typename T> istream& operator>>(istream& is, vector< T >& vc){ for(int i = 0; i < vc.size(); i++) is >> vc[i]; return is; }
    template<typename T> ostream& operator<<(ostream& os, vector< T >& vc){ for(int i = 0; i < vc.size(); i++) os << vc[i] << endl; return os; }
     
    #define ForEach(it,c) for(__typeof (c).begin() it = (c).begin(); it != (c).end(); it++)
    #define ALL(v) (v).begin(), (v).end()
    #define UNQ(s) { sort(ALL(s)); (s).erase( unique( ALL(s)), (s).end());}
    #define fr first
    #define sc second
     
    typedef pair< int , int > Pi;
    typedef pair< int , Pi > Pii;
     
    typedef long long int64;
    const int INF = 1 << 30;
    
    vector< string > str;
    int H, W;
    int dy[] = { -1, -1, -1, 0, 1, 1, 1, 0}, dx[] = { -1, 0, 1, 1, 1, 0, -1, -1};
    queue< Pi > points;
    bool ended[1000][1000];
    
    bool hori_sensei_love_function(){
      bool flag = false;
    
    
      queue< Pi > buff_points;
      queue< Pi > que;
    
      while(!points.empty()){
        Pi p = points.front(); points.pop();
    
        int i = p.first, j = p.second;
        int get = 0;
        if(!ended[i][j] && isdigit(str[i][j])){
          for(int k = 0; k < 8; k++){
            int ny = i + dy[k], nx = j + dx[k];
            get += str[ny][nx] == '.';
          }
          if(str[i][j] - '0' <= get){
            flag = true;
            ended[i][j] = true;
            que.push(Pi( i, j));
          }
        }
    
      }
    
      while(!que.empty()){
        Pi p = que.front(); que.pop();
        int i = p.first, j = p.second;
    
        str[i][j] = '.';
        
        for(int k = 0; k < 8; k++){
          int ny = i + dy[k], nx = j + dx[k];
          if(isdigit( str[ny][nx] ) && str[ny][nx] != '9' && !ended[ny][nx]){
            buff_points.push( Pi( ny, nx));
          }
        }
      }
    
    
      while(!buff_points.empty()){
        points.push( buff_points.front());
        buff_points.pop();
      }
    
      return flag;
    
    }
    
    bool foo(){
      bool flag = false;
    
      for(int i = 0; i < H; i++){
        for(int j = 0; j < W; j++){
          if(isdigit(str[i][j])){
            if(str[i][j] == '9') continue;
    
            int get = 0;
            for(int k = 0; k < 8; k++){
              int ny = i + dy[k], nx = j + dx[k];
              get += str[ny][nx] == '.';
            }
    
            if(str[i][j] - '0' <= get){
              flag = true;
              ended[i][j] = true;
            }
          }
        }
      }
    
      for(int i = 0; i < H; i++){
        for(int j = 0; j < W; j++){
          if(ended[i][j]){
            str[i][j] = '.';
            for(int k = 0; k < 8; k++){
              int ny = i + dy[k], nx = j + dx[k];
              if(isdigit( str[ny][nx] ) && str[ny][nx] != '9' && !ended[ny][nx]){
                points.push( Pi( ny, nx));
              }
            }
          }
        }
      }
    
      return flag;
    }
    
    int main(){
      cin >> H >> W;
    
      str.resize(H);
    
      for(int i = 0; i < H; i++){
        cin >> str[i];
      }
    
      int ret = 0;
      bool changed = foo();
      if(changed) ret++;
    
      while(changed){
        changed = hori_sensei_love_function();
        if(changed) ret++;
      }
      cout << ret << endl;
    }
    
  • 6問目を考え始める
  • 朝のポスターの2分を思い出す
  • 制約的に半分全列挙を疑う
  • 書いてみる
  • 書けた
  • かけてなかった
  • 死んだほうがいい
  • 書けたみたい
  • そこからどうするんだろう
  • セグ木を疑う
  • 必要なところだけ作る例のアレかな
  • 時間がなさそう
  • 時間が残されていない
  • やめた
  • 提出ミスでの死だけは勘弁ということで全てを確認
  • 良さそうと思ったところで終了
実行結果(短そうなやつだけ)
問題1
179204
5415
293725
6000
474688
問題4
1242866
2377989
51767722
9684358
144764153
問題5
1735
993949
994510
343350
442542
問題6(1だけよ)
2816001618489474

2014年11月9日日曜日

PCK2014もうひとつの本選

本選行きたかったなあ
4完0WAで4位でした

  • ジョギングの疲れがとれない
  • (体力が足りないといわれて毎日10km走ってるけどこれは逆効果だ)
  • 疲れがとれなくて眠み生えてる
  • 13:45
  • 問題が先行公開されてたので開く
  • 1問目だけ先に解いてしまおう
  • 問題文を読む
  • 面倒くさそう
  • 読解力がない(1回目)
  • やめたい
  • 線上に点がなかったらなんかやればよさそう
  • 10分くらいだっけな、もうひとつでFAとれたみたい(1問目AC)
  • int main(){
      int N;
    
      cin >> N;
      for(int i = 0; i < N; i++){
        int r, t;
    
        cin >> r >> t;
    
        int shift = (t / 30) * 5; //スタートの番号
        int pos = r / 100; //場所
        bool flag = (t % 30 == 0); //線状か
        
        vector< int > ret;
        ret.push_back(shift + pos);
        if(r % 100 != 0) ret.push_back(shift + pos + 1);
        if(!flag) ret.push_back(shift + pos + 5);
        if(!flag && r % 100 != 0) ret.push_back(shift + pos + 6);
        
        for(int j = 0; j < ret.size(); j++){
          cout << (j == 0 ? "" : " ") << ret[j];
        }
        cout << endl;
      }
    }
    
  • 予選の反省があるから問題にざっと目を通す
  • 6問目と8問目は解けそう感
  • まあいいや2問目
  • やろうとする
  • 誤読に気づく
  • やろうとする
  • 方針が違うことに気づく
  • やろうとする
  • まだ方針違うみたい
  • 読解力がない(2回目)
  • 文字列の長さの合計がどれくらいになるか求めようとする
  • わかんない
  • まあいいか
  • なぜか我が校のサーバーが逝き始める
  • これ顧問が会津いってるからだ
  • 顧問がいないのをいいことに誰かが外部から攻撃してる説
  • これはPCKのライバルからの陰謀だと確信
  • さらに端末の動作が鈍くなってついには動かなくなった
  • これは発狂不可避
  • サーバーの再起動やらなにやらを繰り返す
  • マジで誰だよ
  • まともに問題読めないしコーディングができない
  • ローカルのパソコンでやろう
  • 端末が動かない間に色々整理できたし結果的にはよかったのかもしれない
  • 2問目適当にバックトラックしてサンプル通って提出
  • やったねAC(2問目AC)
  • int w;
    
    void rec(int sum, int idx, string emacs){
      if(abs(sum) > w || pow( 3.0, idx - 2) > w){
        return;
      }
      if(sum == w){ //できたー
        cout << emacs << endl;
        exit(0);
      } else { //できてないー
        rec( sum + (int)pow( 3.0, idx), idx + 1, "+" + emacs);
        rec( sum - (int)pow( 3.0, idx), idx + 1, "-" + emacs);
        rec( sum, idx + 1, "0" + emacs);
      }
    }
    
    int main()
    {
      cin >> w;
      rec( 0, 0, "");
    }
    
  • あのプログラムオーダーどれくらいだろ
  • 無駄な再帰を明確にしてるから、O(logn)より結構大きいくらい
  • 変数名でvim勢を煽っていくスタイル(小声
  • 提出状況を確認したら3問目複数提出あるけど0ACな模様
  • 予選の5問目枠を確信
  • 触れないことにしよう
  • 次何解こう
  • 6問目は僕の頭でも理解できる問題文っぽい
  • O(n^4)の二次元累積和がぱっと見、浮かぶけどTLEだろうな
  • 多少バグらせながらも解く
  • WA(絶望)
  • やっぱバグらせていた
  • すぐ察して提出
  • TLE(妥当)
  • int main()
    {
      int N, mas[302][302] = {{}};
      cin >> N;
      for(int i = 1 ; i <= N ; i++ ){
        for(int j = 1 ; j <= N ; j++ ){
          cin >> mas[i][j];
          mas[i][j] += mas[i-1][j] + mas[i][j-1] - mas[i-1][j-1];
        }
      }
      int ret = -INF;
      for(int i = 1 ; i <= N ; i++ ){
        for(int j = 1 ; j <= N ; j++ ){
          for(int k = 1 ; k <= i ; k++ ){
            for(int l = 1 ; l <= j ; l++ ){
              int all = mas[i][j] - mas[k-1][j] - mas[i][l-1] + mas[k-1][l-1];
              int blank = 0;
              if(abs(i - k) >= 2 && abs(j - l) >= 2){
                blank += mas[i - 1][j - 1] - mas[k][j - 1] - mas[i - 1][l] + mas[k][l];
              }
              ret = max( ret, all - blank);
    
            }
          }
        }
      }
      cout << ret << endl;
    }
    
  • こんなもので通る訳がない(自明
  • きっとDPとかしてO(n^4)をO(n^3)にするんだろう(考察
  • あーーー
  • んーーー
  • ・・・・・・
  • あたまついてない
  • INF個くらい必要そう
  • これは敗北
  • この辺から焦りはじめる
  • 4問目のAC率が高そう、8問目がreal本選erに結構解かれている
  • 8問目読む
  • なんか2008年くらいのPCKにこんな問題あったけどにぶたんで解いたっけ
  • 重さの要素が加わっただけだ
  • とりあえず本を入れる位置を全探で決めてどれくらい入るかは貪欲で求める
  • なぜかバグらせなかった
  • にぶたんはこのときかかなかった
  • 提出
  • TLE
  • 貪欲で求める部分をにぶたんに書き換える
  • 多少バグらせたけどできた
  • ACを確信
  • TLE(困惑)
  • やめた
  • 4問目を読む
  • 問題文ながぽよ
  • 読解力がない(3回目)
  • あーー
  • なんでデッドロックでグラフを作れるんだろう
  • そんなことはどうでもいいらしい
  • 閉路検出してデッドロックが発生するか判定せよ的な感じの問題文になった
  • 解法書いてあるじゃん
  • 本当にそのままなのかな
  • 適当にグラフ作って閉路検出しようとする
  • 閉路検出のスキルが自分にはないことに気づく
  • どうやるんだろう
  • グラフ世界一扱えない
  • こころが沈んできた
  • 強連結成分分解でできる説
  • 実装やだ
  • DFSで試すだけでしょ
  • すべての場合についてデッドロックが発生する
  • 私の頭がデッドロックしそうとかよくわかんないことを考え始める
  • 辺にも使用済かの情報が必要なのか
  • あーこれ巡ったら頂点を使って内容に戻すべきだな
  • なんかできてる
  • つ計算量
  • 大丈夫だろ、提出
  • うっしゃ(4問目AC)
  • typedef vector< vector< Pi > > Graph;
    Graph g;
    int V;
    bool used[300];
    
    int dfs(int idx){
      if(used[idx]) return true;
      used[idx] = true;
      for(int i = 0; i < g[idx].size(); i++){
        if(g[idx][i].second == 0){
         g[idx][i].second = true;
         if(dfs(g[idx][i].first)) return true;
        }
      }
      used[idx] = false;
      return false;
    }
    
    int main()
    {
    
      cin >> V;
      g.resize(200);
      for(int i = 0; i < V; i++){
        int u, d;
        string s;
        cin >> u >> s >> d;
        u--, d--;
        if(s == "lock"){
          g[d + 100].push_back(Pi(u, false));
        } else {
          g[u].push_back(Pi( d + 100, false));
        }
      }
      for(int i = 0; i < 100; i++){
        if(!used[i] && dfs(i)){
          cout << 1 << endl;
          return(0);
        }
      }
    
      cout << 0 << endl;
      return(0);
    }
    
  • こころぴょんぴょんしてきた
  • 3問目を読んでみる
  • 読解力がない(N回目)
  • なんかややこしい
  • 問題文を誤読していることに複数回気づく
  • 読解力がない(INF回目)
  • シミュレーションやるだけ説
  • まあ書く
  • かけたと思ったらサンプル合わない
  • 誤差る
  • 問題文の誤読に気づく
  • 読解力がない(∞回目)
  • なおす
  • でない
  • 問題文の誤読に気づく
  • 多分この問題誤読の回数の最大値を得れた気がする
  • 誤読なくした
  • ソース直した
  • でた
  • 提出
  • うぇい(3問目AC)
  • typedef vector< vector< Pi > > Graph;
    
    int main(){
      int N, R, T, p[100];
      cin >> N >> R >> T;
      for(int i = 0; i < N; i++){
        cin >> p[i];
      }
    
      int stap[1001] = {};
      int pos[100] = {};
      int ret = 0;
      bool first = false;
      for(int i = 1; i <= T; i++){
        for(int j = 0; j < N; j++){
          pos[j] = (pos[j] + p[j]) % R;
        }
    
        for(int k = 0; k < N; k++){
          if(stap[pos[k]] > 0){
            stap[pos[k]]--;
          } else {
            ret++;
          }
        }
        if(first++){
          for(int k = 0; k < N; k++){
            stap[pos[k]]++;
          }
        }
        
      }
      cout << ret << endl;
    }
    
  • こんな簡単なシミュレーションで通るのにあの正答率は何(煽り
  • 再び1位に浮上したらしい
  • あと1時間30分くらいある
  • 5問目を軽く読む
  • 圧倒的木DP感
  • 木DP書いたことない
  • 書けそうもない
  • 8問目再び
  • 計算量O(2 ^ n log m)くらいだよな
  • (後記: 実は大嘘 O(m・2^n log m)っぽい(やばい)) 
  • メモ化した
  • ACを確信
  • TLE(困惑
  • 気になるところを変えてn回出してみるもTLE×n回
  • 高速化の余地なし
  • これもうわかんねえな
  • TLE(引退)
  • たくさんTLE生える
  • 方針は合ってそうだけどなんでだろ
  • つらみがたくさん生える
  • 8回目TLE
  • やめた
  • つかれた
  • 4位だ
  • 5問目解こうとするけど正直解いても順位変わんない
  • 時間がない
  • 本選行きたかったなあ
  • 終了
あとから解いたよ(簡単だった)
5問目 木DPっぽい
int N;
vector< string > node;
vector< vector< int > > edges;
int dp[1000];

int rec(int idx){
  if(dp[idx]) return dp[idx];
  if(edges[idx].empty()) return(1 + (node[idx] == "E?"));

  int64 ret = 0;

  // 選択ノード //
  if(node[idx][0] == 'R'){ /* OR */
    for(int i = 1; i < (1 << edges[idx].size()); i++){
      int64 ret1 = 1;
      for(int j = 0; j < edges[idx].size(); j++){
        if((i >> j) & 1){
          (ret1 *= rec(edges[idx][j])) %= 1000000007;
        }
      }
      ret += ret1;
    }
    if(node[idx] == "R?") ret++;
  } else if(node[idx][0] == 'A'){ /* ALT */
    for(int i = 0; i < edges[idx].size(); i++){
      (ret += rec(edges[idx][i])) %= 1000000007;
    }
    if(node[idx] == "A?") ret++;
  } else { // 物質ノード //
    ret = 1;
    for(int i = 0; i < edges[idx].size(); i++){
      (ret *= rec(edges[idx][i])) %= 1000000007;
    }
    if(node[idx] == "E?") ret++;
  }
  return(dp[idx] = ret % 1000000007);
}

int main(){
  cin >> N;
  node.resize(N);
  edges.resize(N);

  for(int i = 0; i < N; i++){
    cin >> node[i];
  }
  for(int i = 0; i < N - 1; i++){
    int a, b;
    cin >> a >> b;
    a--, b--;
    edges[a].push_back(b);
  }
  cout << rec(0) << endl;
}
8問目 メモ化じゃ解けないやこれ。DPしてにぶたんするだけ
途中でint64生えてるのとかにぶたんがちょっとおかしかったりするのは頭悪いデバッグのおかげ
typedef long long int64;
int64 M, N;
int64 w[200004], t[200004];
int64 c[15], b[15];
int64 dp[1 << 15];


int64 get_sum_w(int64 a, int64 b){ // [a,b]
  if(a == 0) return w[b];
  return(w[b] - w[a - 1]);
}
int64 get_sum_t(int64 a, int64 b){
  if(a == 0) return t[b];
  return(t[b] - t[a - 1]);
}

int64 get_donyoku(int64 idx, int64 dan){
  int64 max_weight = c[dan], max_width = b[dan];

  int64 pos = INF;

  int64 row = idx, high = M;
  while(row + 1 < high){
    int64 mid = (row + high) / 2;
    if(get_sum_w( idx, mid) <= max_weight) {
      row = mid + 1;
    } else {
      high = mid;
    }
  }

  if(get_sum_w( idx, row) > max_weight)  pos = min( pos, row);
  else if(get_sum_w( idx, row + 1) > max_weight) pos = min( pos, row + 1);
  else if(get_sum_w( idx, row + 2) > max_weight) pos = min( pos, row + 1);

  row = idx, high = M;
  while(row + 1 < high){
    int64 mid = (row + high) / 2;
    if(get_sum_t( idx, mid) > max_width) {
      high = mid;
    } else {
      row = mid + 1;
    }
  }

  if(get_sum_t( idx, row) > max_width)  pos = min( pos, row);
  else if(get_sum_t( idx, row + 1) > max_width) pos = min( pos, row + 1);
  else if(get_sum_t( idx, row + 2) > max_width) pos = min( pos, row + 1);

  if(pos == INF) return idx;
  return pos;
}

int main(){
  scanf("%d %d", &M, &N);
  w[M] = INF, t[M] = INF;
  w[M + 1] = INF, t[M + 1] = INF;
  for(int i = 0; i < M; i++){
    scanf("%d %d", &w[i], &t[i]);
    if(i != 0){
      w[i] += w[i - 1];
      t[i] += t[i - 1];
    }
  }
  for(int i = 0; i < N; i++){
    scanf("%d %d", &c[i], &b[i]);
  }
  fill_n( dp, 1 << 15, -1);
  dp[0] = 0;
  for(int i = 0; i < (1 << 15); i++){
    if(dp[i] == -1) continue;
    for(int j = 0; j < N; j++){
      if(!((i >> j) & 1)){
        dp[i|(1 << j)] = max( dp[i|(1 << j)], get_donyoku(dp[i], j));
      }
    }
  }
  cout << *max_element( dp, dp + (1 << 15)) << endl;
}
次はJOIだ
JOI頑張りましょ

2014年11月2日日曜日

CODEFESTIVAL2014 予選B

ブログの存在を忘れていた
スーパーコン本戦とかPCK予選(落ち)とか色々あったけど過去のことは忘れたな
コードフェスティバルの予選が合ったらしい(参加権ない)
予選Aは20位で1ページ目に乗ってて実力に見合わない

予選B
  • 直前にキーボードの3(#)キーが壊れる
  • 治らない
  • なんにも準備してない
  • スタート
  • シャープ打てないとtweetしようとしたところで「しゃーぷ」を変換すれば出来る事が判明
  • A問題FA狙うも9秒ACという人外が現れて引退
  • MAXとるだけっぽい(A00:20AC)
  • B問題
  • 足すだけっぽい
  • 書く
  • ACやったね(B02:43AC)
  • 順位表を確認
  • D問題ACしてる人がいるからそっちを先に解こう
  • Dが一番簡単という風潮??
  • DP?
  • 書く
  • 問題誤読、なぜか増加部分列的な感じだと思ってた
  • 書く
  • 書けない
  • 更に問題誤読
  • 一瞬セグ木が頭の片隅に浮かぶけどオーダー大丈夫か?
  • やめよう
  • C問題読む
  • 変な解法しそうだなあ
  • どうせC問題
  • 文字の数数えて使わないといけない数を求める
  • 良い感じにやる
  • 反例なんて考えられない頭だからこのまま提出
  • 意外にもACしてる(C36:26AC)
  • 順位逝ってしまうから保険欲しい
  • 普通に数えるやつを書く(D38:59TLE部分点30)
  • セグ木のやつO(nlog^2n)か
  • O(10^8)くらい??
  • んーー(関数電卓紛失)
  • 書く
  • にぶたんばぐる
  • にぶたん世界一書けない
  • にぶたんした後の微妙な足し算めんどい
  • 番兵置こう(いらなかった)
  • 提出(D63:21AC)
  • 1.5sかかってる
  • cinにしたらどうなるのだろう
  • TLE
  • 終わり(44位)
Code
A
#include<bits/stdc++.h>
using namespace std;
int main(){
  int a, b;
  cin >> a >> b;
  cout << max( a, b) << endl;
}
B
#include<bits/stdc++.h>
using namespace std;
typedef long long int64;
int main(){
  int n, k, a[100000];
  cin >> n >> k;
  int64 sum = 0;
  for(int i = 0; i < n; i++){
    cin >> a[i];
    sum += a[i];
    if(k <= sum){
      cout << i + 1 << endl;
      return(0);
    }
  }
}
C
#include<bits/stdc++.h>
using namespace std;
typedef pair< int , int > Pi;
int main(){
  string s1, s2, s3;
  cin >> s1 >> s2 >> s3;
  int cnt1[26] = {}, cnt2[26] = {}, cnt3[26] = {};
  for(int i = 0; i < 26; i++) cnt1[i] += count(s1.begin(), s1.end(), (char)('A' + i));
  for(int i = 0; i < 26; i++) cnt2[i] += count(s2.begin(), s2.end(), (char)('A' + i));
  for(int i = 0; i < 26; i++) cnt3[i] += count(s3.begin(), s3.end(), (char)('A' + i));
 
  
  int need1 = 0, need2 = 0;
  bool flag = true;
  for(int i = 0; i < 26; i++){
    if(cnt2[i] < cnt3[i]){
      need1 += cnt3[i] - cnt2[i];
      if(cnt2[i] + cnt1[i] < cnt3[i]) flag = false;
    }
  }
  for(int i = 0; i < 26; i++){
    if(cnt1[i] < cnt3[i]){
      need2 += cnt3[i] - cnt1[i];
    }
  }
  if(need1 > s1.size() / 2 || need2 > s2.size() / 2 || !flag)  cout << "NO" << endl;
  else cout << "YES" << endl;
}
D
#include<bits/stdc++.h>
using namespace std;
typedef long long int64;
typedef pair< int , int > Pi;
int h[100002];
#define MAX 400000
int n, seg[MAX * 2 - 1];
const int INF = 1 << 30;
void update( int i, int x){
  i += n - 1;
  seg[i] = x;
  while(i > 0){
    i = ( i - 1 ) / 2;
    seg[i] = max( seg[i * 2 + 1], seg[i * 2 + 2]);
  }
}
int query( int a, int b, int k = 0, int l = 0, int r = n){
  if( r <= a || b <= l ) return -1;
  if( a <= l && r <= b ) return seg[k];
  int vl = query( a, b, k * 2 + 1, l, (l + r) / 2);
  int vr = query( a, b, k * 2 + 2, (l + r) / 2, r);
  return max( vl, vr);
}
void init( int& size){
  n = 1;
  while( n < size ) n *= 2;
}
 
int main(){
  int size;
  scanf("%d", &size);
  init(size);
  h[0] = -INF;
  for(int i = 1; i <= size; i++){
    scanf("%d", &h[i]);
    update( i, h[i]);
  }
  h[size + 1] = INF;
  for(int i = 1; i <= size; i++){
    int cost = 0;
    int row = 0, high = i - 1;
    while(high - row > 0){
      int mid = (high + row + 1) >> 1;
      if(query(mid, high + 1) > h[i]){
        row = mid;
      } else {
        high = mid - 1;
      }
    }
    cost += i - high - 1;
    
    row = i + 1, high = size + 1;
    
    while(high - row > 0){
      int mid = (high + row) / 2;
      if(query( row, mid + 1) > h[i]){
        high = mid;
      } else {
        row = mid + 1;
      }
    }
    
    cost += row - i - 1;
    
    printf("%d\n", cost);
  }
}

2014年3月23日日曜日

AOJ1508 RMQ

解法


Treap木を本とかを大分参考にしながら実装してみた。
割と実装楽しい。

ソース


#include<bits/stdc++.h>
using namespace std;
const int INF = 1 << 30;
struct Treap {
  struct node{
    int value; // 値
    node *left, *right; // *左, *右:
    int priority; // 優先度
    int cnt; // 部分木のサイズ
    //  int sum; // 部分木の和
    int small; //部分木の最小値
    node( int v) : value(v), priority(rand()), cnt(1), /*sum(v),*/ small(v){
      left = right = NULL;
    }
  };
  
  node *root;
  Treap():root(NULL){}
  
  int count( node *t){ return !t ? 0 : t->cnt; }
  //int sum( node *t)  { return !t ? 0 : t->sum; }
  int mini( node *t) { return !t ? INF : t->small; }
  
  node* update( node* t) {
    t -> cnt = count( t -> left) + count( t -> right) + 1;
    // t -> sum = sum( t -> left) + sum( t -> right) + t -> value;
    t -> small = min( min( mini( t -> left), mini( t -> right)), t -> value);
    return t;
  }
  node* merge( node* l, node* r){
    if(!l || !r) return l? l : r;
    if(l -> priority > r -> priority) {
      l -> right = merge( l -> right, r);
      return update(l);
    } else {
      r -> left = merge( l, r -> left);
      return update(r);
    }
  }
  pair< node*, node* > split( node* t, int k){ // [0,k),[k,n)
    if(!t) return make_pair((node*)NULL,(node*)NULL);
    if(k <= count( t -> left)){
      pair< node*, node* > s = split( t -> left, k);
      t -> left = s.second;
      return make_pair( s.first, update(t));
    }else{
      pair< node*, node* > s = split( t -> right, k - count( t -> left) - 1);
      t -> right = s.first;
      return make_pair( update(t), s.second);
    }
  }
  
  node* insert( node* t, int k, int val){
    pair< node*, node* > s = split( t, k);
    t = merge( s.first, new node( val));
    return update(merge( t, s.second));
  }
  
  node* erase( node* t, int k){
    pair< node*, node* > s1, s2;
    s1 = split( t, k + 1);
    s2 = split( s1.first, k);
    t = merge( s2.first, s1.second);
    return update(t);
  }
  
  node* find( node* t, int k){
    int c = count(t -> left);
    if(k < c)       return find( t -> left, k);
    else if(k > c)  return find( t -> right, k - c - 1);
    else return t;
  }
  void insert( int k, int v){ root = insert( root, k, v);}
  void erase( int k) { root = erase( root, k);}
  node* find( int k) { return find( root, k); }
};
  
int main(){
  int n, q;
  Treap tree;
  
  scanf("%d %d", &n, &q);
  for(int i = 0, a ; i < n ; i++ ){
    scanf("%d", &a);
    tree.insert( i, a);
  }
  while(q--){
    int x, y, z;
    scanf("%d %d %d", &x, &y, &z);
    if(x == 0){
      z++;
      pair< Treap::node*, Treap::node* > a, b, c;
      c = tree.split( tree.root, z);     // [0,z] [z + 1,n)
      b = tree.split( c.first , z - 1);  // [0,z) [z]
      a = tree.split( b.first , y);     //  [0,y) [y,z)
  
      tree.root = tree.merge( a.first, b.second); // [0,y) + [z]
      tree.root = tree.merge( tree.root, a.second); // root + [y,z)
      tree.root = tree.merge( tree.root, c.second); // root + [z+1,n)
  
      //ふええふえぇふぇぇ(むずかしいね
    } else if(x == 1){
      z++;
 
      pair< Treap::node*, Treap::node* > p, q;
      p = tree.split( tree.root, y);
      q = tree.split( p.second, z - y);
      printf("%d\n", tree.mini(q.first));
      tree.root = tree.merge( p.first, tree.merge( q.first, q.second));
    } else {
      tree.erase(y);
      tree.insert( y, z);
    }
  }
}

AOJ2402 天の川

解法


星の変な入力を頑張って5辺にしてDijkstra。

ソース


typedef pair< double , int > Pi;
bool used[100];
double info[100][100];
int n, m, l;
L stars[100][5];
 
void add( int x, int y, int a, int r, const int z){
  G hosi(5);
  for(int i = 0 ; i < 5 ; i++ ){
    double theta = Degree_to_Radian(a + 72 * i);
    double nx = r * sin( theta ), ny = r * cos( theta );
    hosi[i] = P( x - nx, y + ny);
  }
  for(int i = 0 ; i < 5 ; i++ ){
    stars[z][i] = L( hosi[i * 2 % 5], hosi[(i + 1) * 2 % 5]);
  }
}
double dist( LLL a, LLL b){
  double ret = INF;
  for(int i = 0 ; i < a.size() ; i++ ){
    for(int j = 0 ; j < b.size() ; j++ ){
      ret = min( ret, distancion( a[i], b[i]));
    }
  }
  return ret;
}
double Dijkstra(){
  priority_queue< Pi , vector< Pi > , greater< Pi > > que;
  fill_n( used, 100, false);
  que.push( Pi( 0.0, m));
  while(!que.empty()){
    Pi p = que.top(); que.pop();
    if(p.sc == l) return p.fr;
    if(used[p.sc]++) continue;
    for(int i = 0 ; i < n ; i++ )
      que.push( Pi( info[p.sc][i] + p.fr, i));
  }
}
  
int main(){
  while(cin >> n >> m >> l, l){
    m--, l--;
    for(int i = 0 ; i < n ; i++ ){
      int x, y, a, r;
      cin >> x >> y >> a >> r;
      add( x, y, a, r, i);
    }
  
    for(int i = 0 ; i < n ; i++ ){
      for(int j = i + 1 ; j < n ; j++ ){
        double dist = INF;
        for(int a = 0 ; a < 5 ; a++ ){
          for(int b = 0 ; b < 5 ; b++ ){
            dist = min( dist, distancion( stars[i][a], stars[j][b]));
          }
        }
        info[i][j] = info[j][i] = dist;
      }
    }
    cout << fixed << setprecision(10) << Dijkstra() << endl;
  }
}

AOJ2545 ライオン

解法


全探する。考えられる組み合わせをすべて挙げればいい感じにできる。
できるだけライオンを檻の中に多く入れたいので、あんな感じ(以下ソース参照)に檻に入れられる最大値からループを回す。

ソース


#include<iostream>
using namespace std;
 
int n, x, m, l[10], r[10], s[10];
int ret[6];
 
bool rec( int now, int sum){
  if(now == n){
 
    int sum[6] = {};
    for(int i = 0 ; i < n ; i++){
      sum[i + 1] = sum[i] + ret[i];
    }
    for(int i = 0 ; i < m ; i++ ){
      if(sum[r[i]] - sum[l[i] - 1] != s[i]) return false;
    }
    for(int i = 0 ; i < n ; i++ ){
      cout << (i  ? " " : "") << ret[i];
    }
    cout << endl;
    return true;
 
  }
  for(int i = x ; i >= 0 ; i--){
    ret[now] = i;
    if(rec( now + 1, sum - i)) return true;
  }
  return false;
}
 
int main(){
  cin >> n >> x >> m;
  for(int i = 0; i < m; i++){
    cin >> l[i] >> r[i] >> s[i];
  }
  if(!rec(0,m)) cout << "-1\n";
}

AOJ1175 そして,いくつになった?

解法


ふぇぇって考えてるとbitDPに帰着すると思う。
前処理で円と円の交差判定が必要で,
円Oと円O'間の距離が Oの半径 + O'の半径未満だったら交差してないと判定する。
距離はsqrtとらずに整数でやると誤差らずに出来て良かった。

ソース


#include<iostream>
#include<algorithm>
#include<map>
#include<cmath>
#include<algorithm>
using namespace std;
typedef pair < int , int > Pt;
bool dp[1 << 24];
Pt pts[24];
int n, r[24], c[24];
int hoge[24];
const int INF = 1 << 28;
bool intersect( Pt a, Pt b, int r1, int r2){
  return pow( a.first - b.first, 2) + pow( a.second - b.second, 2) < pow( r1 + r2, 2);
}
 
int rec( int bit){
  if(dp[bit]++) return -INF;
  int ret = 0;
 
  for(int i = 0 ; i < n ; i++ ){
    if((bit >> i) & 1){
      for(int j = i + 1 ; j < n ; j++ ){
        if( (bit >> j) & 1 && c[i] == c[j] && !(bit & hoge[i]) && !(bit & hoge[j])){
          ret = max( ret, rec( bit & ~(1 << i) & ~(1 << j)) + 2);
        }
      }
    }
  }
  return ret;
}
int main()
{
  while(cin >> n, n){
    fill_n( dp, 1 << 24 , false);
    fill_n( hoge, 24 , 0);
 
    for(int i = 0 ; i < n ; i++ ){
      cin >> pts[i].first >> pts[i].second >> r[i] >> c[i];
      for(int j = 0 ; j < i ; j++ ){
        if(intersect(pts[i],pts[j],r[i],r[j])) hoge[i] |= 1 << j;
      }
    }
    cout << rec((1 << n) - 1) << endl;
  }
}

2014年2月15日土曜日

AOJ0187 Stoning Fortune

解法


どれか二線の交点がなかったら凶。
あったら、3つの交点を求めてヘロンの公式S=√s(s-a)(s-b)(s-c)で面積を求めてはっぴー

ソース


int main(){
  L ls[3];
  int x1[3], y1[3], x2[3], y2[3];
  while( cin >> x1[0] >> y1[0] >> x2[0] >> y2[0], x1[0]|y1[0]|x2[0]|y2[0] ){
    for(int i = 1 ; i < 3 ; i++ ){
      cin >> x1[i] >> y1[i] >> x2[i] >> y2[i];
    }
    for(int i = 0 ; i < 3 ; i++ ){
      ls[i] = L( P( x1[i], y1[i]), P( x2[i], y2[i]));
    }
 
    G triangle(3);
    bool flag = true;
    for(int i = 0 ; i < 3 ; i++ ){
      const int NEXT = ( i + 1 ) % 3;
      if(!intersect( ls[i], ls[NEXT])){
        flag = false;
        break;
      }else{
        triangle[i] = crosspoint( ls[i], ls[NEXT]);
      }
    }
 
    double s = (abs(triangle[0]-triangle[1])+abs(triangle[1]-triangle[2])+abs(triangle[2]-triangle[0])) / 2;
    double area = sqrt(s * ( s - abs(triangle[0] - triangle[1])) * ( s - abs(triangle[1] - triangle[2])) * ( s - abs(triangle[2] - triangle[0])));
    if(!flag || area < EPS) cout << "kyo" << endl;
    else if(area < 100000) cout << "syo-kichi" << endl;
    else if(area < 1000000) cout << "kichi" << endl;
    else if(area < 1900000) cout << "chu-kichi" << endl;
    else cout << "dai-kichi" << endl;
  }
}

AOJ0091 Blur

解法


BFS。左上から見ていって、滴数 < 0か垂らしても残った時に枝刈りした。
これでVolume0全完。

ソース


#include<bits/stdc++.h>
using namespace std;

int q, mas[10][10];
int draw[][5][5] = {
  /*Small*/
  {{ 0, 0, 1, 0, 0},
   { 0, 1, 1, 1, 0},
   { 0, 0, 1, 0, 0}},
  //*midium*/
  {{ 0, 0, 1, 1, 1},
   { 0, 0, 1, 1, 1},
   { 0, 0, 1, 1, 1}},
  /*large*/
  {{ 0, 0, 1, 0, 0},
   { 0, 1, 1, 1, 0},
   { 1, 1, 1, 1, 1},
   { 0, 1, 1, 1, 0},
   { 0, 0, 1, 0, 0}},
};

bool check( int y, int x, int w){
  for(int i = 0 ; i < 5 ; i++ ){
    for(int j = 0 ; j < 5 ; j++ ){
      if(mas[y + i][x + j - 2] - draw[w][i][j] < 0) return false;
    }
  }
  return true;
}

void paint( int y, int x, int w){
  for(int i = 0 ; i < 5 ; i++ ){
    for(int j = 0 ; j < 5 ; j++ ){
      mas[y + i][x + j - 2] -= draw[w][i][j];
    }
  }
}

void repaint( int y, int x, int w){
  for(int i = 0 ; i < 5 ; i++ ){
    for(int j = 0 ; j < 5 ; j++ ){
      mas[y + i][x + j - 2] += draw[w][i][j];
    }
  }
}

bool rec( int y, int x, int n){
  if( n < 0 ) return false;
  if( y == 10 ) return n == 0;
  if( mas[y][x] == 0 ) return rec( y + (x == 9), (x + 1) % 10, n);
  for(int i = 0 ; i < 3 ; i++ ){
    if(!check( y, x, i)) continue;
    paint( y, x, i);
    if(rec( y, x, n - 1)){
      cout << x + (i == 1) << " " << y + 1 + (i == 2) << " " << i + 1 << endl;
      return true;
    }
    repaint( y, x, i);
  }
  return false;
}

int main(){
  cin >> q;
  for(int i = 0 ; i < 10 ; i++ ){
    for(int j = 0 ; j < 10 ; j++ ){
      cin >> mas[i][j];
    }
  }
  rec( 0, 0, q);
 }

2014年2月8日土曜日

AOJ0560 惑星探査

解法


二次元累積和を実装していい感じにやる

ソース


#include<iostream>  
#include<vector>  
#include<algorithm>  
#include<string>  
   
using namespace std;  
int mas[1001][1001][3];  
int main(){  
   
  int M, N, K;  
  string tmp = "JOI";  
   
  cin >> M >> N;  
  cin >> K;  
  for(int i = 1 ; i <= M ; i++ ){  
    for(int j = 1 ; j <= N ; j++ ){  
      char c;  
      cin >> c;  
      for(int k = 0 ; k < 3 ; k++ ){  
        mas[i][j][k] = mas[i-1][j][k] + mas[i][j-1][k] - mas[i-1][j-1][k];  
      }  
      mas[i][j][tmp.find(c)]++;  
    }  
  }  
  for(int i = 0 ; i < K ; i++ ){  
    int a, b, c, d;  
    cin >> a >> b >> c >> d;  
    for(int j = 0 ; j < 3 ; j++ ){  
      cout << (j?" ":"") << mas[c][d][j] + mas[a-1][b-1][j] - mas[a-1][d][j] - mas[c][b-1][j];  
    }  
    cout << endl;  
  }  
}  

AOJ1183 鎖中経路

解法


2つの円の交点を通る線分に交わっているか確かめながら、Dijkstraした。


ソース


#include<complex>
#include<algorithm>
#include<vector>
#include<map>
#include<iomanip>
#include<iostream>
#include<queue>
using namespace std;
#define fr first
#define sc second
 
struct line: public vector< complex<double> >{
  line(){};
  line( const complex<double>& a, const complex<double>& b){
    push_back(a);
    push_back(b);
  }
};
struct circle {
  complex<double> p; double r;
  circle():p(0,0),r(0){};
  circle(const complex<double> &p, double r) : p(p),r(r){}
};
 
typedef complex < double > P;
typedef line               L;
typedef pair < P, P >      Ls;
typedef vector< P >        G;
typedef vector< P >        Ps;
typedef vector< L >        LLL;
typedef circle             C;
const double EPS = 1e-9;
const double INF = 1e8;
 
bool   eq(P,P); //点:点 一緒か
double cross(P,P); //外積
double dot(P,P); //内積
int    ccw(P,P,P); //3点の位置関係
bool   parallel(L,L); // 直線//直線
bool   orthogonal(L,L); //直線⊥直線
bool   intersect(L,L); //線分:線分交差
bool   intersect(L,P); //線分:点交差
bool   intersect(Ls,Ls); //直線:直線交差
bool   intersect(Ls,L); //直線:線分交差
bool   intersect(Ls,P); //直線:点交差
int    intersect(C,L); //円:線分交点数
double distance(L,L); //線分:線分の距離
double distance(L,P); //線分:点の距離
double distance(P,P); //点:点の距離
double distance(Ls,P); //直線:点距離
double distance(Ls,Ls); //直線:直線距離
double distance(Ls,L); //直線:線分距離
P      crosspoint(L,L); //線分:線分交点計算
L      crosspoint(C,Ls); //円:直線交点計算
L      crosspoint(C,L); //円:線分交点計算
Ps     crosspoint(C,C); //円:円交点計算
int    contains(G,P); //GがPが包容か
double area2(G); //Gの面積
bool   isconvex(G); //凸性判定
Ps     convex(G); //凸包
 
 
namespace std {
  bool operator < (const P& a, const P& b) {
    return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
  }
}
L llcomb(Ls a){
  L line( a.fr, a.sc);
  return line;
}
Ls llrcomb(L a){
  Ls line( a[0], a[1]);
  return line;
}
bool eq( P a, P b){
  return abs( a - b) < EPS;
}
double cross( P a, P b){
  return imag( conj(a) * b);
}
double dot( P a, P b){
  return real( conj(a) * b);
}
P projection( L l, P p) {
  double t = dot( p - l[0], l[0] - l[1]) / norm( l[0] - l[1]);
  return l[0] + t * ( l[0] - l[1]);
}
 
int ccw( P a, P b, P c){
  b -= a, c -= a;
  if(cross(b,c) > EPS)    return 1;  // a → b で 時計方向におれて c
  if(cross(b,c) < -EPS)    return -1; // a → b で 反時計方向におれて c
  if(dot(b,c) < -EPS)      return 2;  // c -- a -- b
  if(norm(b) < norm(c) - EPS) return -2; // a -- b -- c
                        return 0;  // a -- c -- b
}
bool intersect( L a, L b){
  return ccw( a[0], a[1], b[0]) * ccw( a[0], a[1], b[1]) <= 0 &&
    ccw( b[0], b[1], a[0]) * ccw( b[0], b[1], a[1]) <= 0;
}
bool intersect( L a, P p){
   return abs( a[0] - p) + abs( a[1] - p) - abs( a[1] - a[0]) < EPS;
}
bool intersect( Ls l, Ls m) {
  return abs(cross(l.sc-l.fr, m.sc-m.fr)) > EPS ||
         abs(cross(l.sc-l.fr, m.fr-l.fr)) < EPS;
}
bool intersect(Ls l, L s) {
  return cross( l.sc - l.fr, s[0] - l.fr) *      // s[0] is left of l
         cross( l.sc - l.fr, s[1] - l.fr) < EPS; // s[1] is right of l
}
bool intersect(Ls l, P p) {
  return abs( cross( l.sc - p, l.fr - p)) < EPS;
}
int intersect( C c, L l){
  if( norm( projection( l, c.p) - c.p) - c.r * c.r > EPS) return 0;
  const double d1 = abs( c.p - l[0]), d2 = abs( c.p - l[1]);
  if( d1 < c.r + EPS && d2 < c.r + EPS) return 0;
  if( d1 < c.r - EPS && d2 > c.r + EPS
      || d1 > c.r + EPS && d2 < c.r - EPS ) return 1;
  const P h = projection(l, c.p);
  if( dot( l[0] - h, l[1] - h) < 0) return 2;
  return 0;
}
double distance( L s, P p){
  P r = projection(s, p);
 
  if ( intersect( s, r)) return abs( r - p);
  return min( abs( s[0] - p), abs( s[1] - p));
}
double distance( L a, L b){
  if(intersect( a, b)) return 0;
  return min( min( distance( a, b[0]), distance( a, b[1])),
              min( distance( b, a[0]), distance( b, a[1])));
}
double distance( Ls l, P p) {
  return abs(p - projection( llcomb(l), p));
}
double distance( Ls l, Ls m) {
  return intersect(llcomb(l), llcomb(m)) ? 0 : distance(llcomb(l), m.fr);
}
double distance( Ls l, L s) {
  if (intersect(l, s)) return 0;
  return min(distance(l, s[0]), distance(l, s[1]));
}
double distance( P a, P b){
  return abs( a - b);
}
bool parallel( L a, L b){
  return abs( cross( a[1] - a[0], b[1] - b[0])) < EPS;
}
bool orthogonal( L a, L b){
  return dot( a[0] - a[1], b[0] - b[1]) < EPS;
}
#define curr(P,i) P[i]
#define next(P,i) P[(i+1)%P.size()]
#define prev(P, i) P[(i+P.size()-1) % P.size()]
enum { OUT, ON, IN };
int conteins(G Q, P p){
  bool in = false;
  for(int i = 0 ; i < Q.size() ; i++ ){
    P a = curr(Q,i) - p, b = next(Q,i) - p;
    if(imag(a) > imag(b)) swap(a,b);
    if(imag(a) <= 0 && 0 < imag(b) && cross(a,b) < 0) in = !in;
    if(cross(a,b) == 0 && dot(a,b) <= 0) return ON;
  }
  return in ? IN : OUT;
}
double area2(G p){
  double A = 0;
  for (int i = 0; i < p.size(); ++i){
    A += cross(curr(p, i), next(p, i));
  }
  return A;
}
bool isconvex(G p) {
  for (int i = 0; i < p.size(); ++i){
    if (ccw(prev(p, i), curr(p, i), next(p, i)) > 0) return false;
  }
  return true;
}
Ps convex(Ps ps) { //n>=3
  int k = 0;
  sort(ps.begin(), ps.end());
  Ps ch(2 * ps.size());
  for (int i = 0; i < ps.size(); ch[k++] = ps[i++]){
    while (k >= 2 and ccw(ch[k-2], ch[k-1], ps[i]) <= 0) --k;
  }
  for (int i = ps.size()-2, t = k+1; i >= 0; ch[k++] = ps[i--]){
    while (k >= t and ccw(ch[k-2], ch[k-1], ps[i]) <= 0) --k;
  }
  ch.resize(k-1);
  return ch;
}
P crosspoint(L l, L m) {
  double A = cross(l[1] - l[0], m[1] - m[0]);
  double B = cross(l[1] - l[0], l[1] - m[0]);
  if (abs(A) < EPS && abs(B) < EPS) return m[0]; // same line
  return m[0] + B / A * (m[1] - m[0]);
}
L crosspoint( C c, Ls l) {
  const P hp = projection( llcomb(l), c.p), h =  hp - c.p;
  const double d2 = norm(h);
  P v = sqrt( c.r * c.r - d2) * ( l.sc - l.fr) / abs( l.sc - l.fr);
  return L(hp - v, hp + v);
}
L crosspoint( C c, L l) {
  if(intersect(c, l) == 2) return crosspoint(c, llrcomb(l));
  L ret = crosspoint(c, llrcomb(l));
  if(dot(l[0] - ret[0], l[1] - ret[0]) < 0) ret[1] = ret[0];
  else ret[0] = ret[1];
  return ret;
}
Ps crosspoint(C c1, C c2){
  double d = abs(c1.p - c2.p);
  double s = (c1.r + c2.r + d) / 2;
  double S = sqrt( s * ( s - c1.r) * ( s - c2.r) * ( s - d));
  double h = 2 * S / d;
  P v = ( c2.p - c1.p) / ( abs( c2.p - c1.p));
  double m = sqrt( c1.r * c1.r - h * h);
  Ps ret;
  ret.push_back( c1.p + m * v + h * v * P(0,1));
  ret.push_back( c1.p + m * v - h * v * P(0,1));
  return ret;
}
struct dC{
  double cost;
  P pos;
  int nowi,nowj;
  bool operator < (const dC &left) const {
    return cost > left.cost;
  }
};
L make_2_cross(C c1, C c2){
  Ps a(crosspoint( c1, c2));
  return L( a[0], a[1]);
}
 
int main(){
  C prev, now;
  int n;
 
  while(cin >> n , n){
    LLL ls;
 
    cin >> prev.p.real() >> prev.p.imag() >> prev.r;
    ls.push_back( L( prev.p, prev.p));
 
    for(int i = 1 ; i < n ; i++ ){
      cin >> now.p.real() >> now.p.imag() >> now.r;
      ls.push_back( make_2_cross( prev, now));
      prev = now;
    }
    ls.push_back( L( prev.p, prev.p)); // G
 
    priority_queue< dC > que;
    que.push((dC){ 0, ls[0][0], 0, 0});
    bool used[101][2] = {{}};
    double ret = INF;
    while(!que.empty()){
      dC p = que.top();
      que.pop();
      if(p.nowj == n){
        ret = p.cost;
        break;
      }
      if(used[p.nowj][p.nowi]++) continue;
      for(int i = 0 ; i < 2 ; i++ ){
        for(int j = p.nowj + 1 ; j <= n ; j++ ){
          L l = L( p.pos, ls[j][i]);
 
          bool flag = true;
          for(int k = j - 1 ; k > p.nowj ; k-- ){
            if(!intersect( l, ls[k])){
              flag = false;
              break;
            }
          }
          if(flag) que.push( (dC){ abs( l[0] - l[1]) + p.cost, l[1], i, j});
        }
      }
    }
    cout << fixed << setprecision(7) << ret << endl;
  }
}

AOJ1182 鉄道乗り継ぎ

解法


ワーシャった(小並感)
最初はワーシャって会社別に各駅までの最短距離を求める。
その次は、与えられたグラフを20000くらい(距離≦200 * 駅数≦100 より)までシュミレートして愚直に運賃を求める。
で、それを最初のグラフと照らし合わせながら、最短距離を運賃に変えたグラフにする。ついでに会社もまとめる。
最後にもう一回ワーシャって最安運賃を求める。

ソース


#include<iostream>
#include<queue>
#include<map>
 
using namespace std;
 
typedef pair < int , int > Pi;
const int INFTY = ( 1 << 28 );
 
int main(){
  int n, m, c, s, g;
  int station[21][101][101];
  int COST[21][20001];
 
  while(cin >> n >> m >> c >> s >> g, n){
    fill_n(**station, 21*101*101, INFTY);
    fill_n(*COST, 21 * 20001, 0);
    for(int i = 0 ; i < 21 ; i++ ){
      for(int j = 0 ; j < 101 ; j++ ) station[i][j][j] = 0;
    }
    for(int i = 0 ; i < m ; i++ ){
      int x, y, d, c;
      cin >> x >> y >> d >> c;
      station[c][x][y] = station[c][y][x] = min( station[c][x][y], d);
    }
 
    //わーしゃる
    for(int i = 1 ; i <= c ; i++ ){
      for(int j = 1 ; j <= n ; j++ ){
        for(int k = 1 ; k <= n ; k++ ){
          for(int l = 1 ; l <= n ; l++ ){
            station[i][k][l] = min( station[i][k][l], station[i][k][j] + station[i][j][l]);
          }
        }
      }
    }
    int p[21];
    for(int i = 1 ; i <= c ; i++ ){
      cin >> p[i];
    }
    int cost[52], dist[52];
    for(int i = 1 ; i <= c ; i++ ){
      fill_n( dist, 52, 0);
      fill_n( cost, 52, 0);
      for(int j = 1 ; j < p[i] ; j++ ){
        cin >> dist[j];
      }
      for(int j = 1 ; j <= p[i] ; j++ ){
        cin >> cost[j];
      }
      int diff = cost[1];
      int pos = 1;
      for(int j = 1 ; j < 20001 ; j++ ){
        if( pos < p[i] && dist[pos] < j) pos++;
        COST[i][j]= COST[i][j-1] + cost[pos];
      }
    }
    int ret[101][101];
    fill_n( *ret, 101 * 101, INFTY);
    for(int i = 1 ; i <= c ; i++ ){
      for(int j = 1 ; j <= n ; j++ ){
        for(int k = 1 ; k <= n ; k++ ){
          if(station[i][j][k] != INFTY) ret[j][k] = min( ret[j][k], COST[i][station[i][j][k]]);
        }
      }
    }
    for(int i = 1 ; i <= n ; i++ ){
      for(int j = 1 ; j <= n ; j++ ){
        for(int k = 1 ; k <= n ; k++ ){
          ret[j][k] = min( ret[j][k], ret[j][i] + ret[i][k]);
        }
      }
    }
 
    if(ret[s][g] == INFTY) cout << -1 << endl;
    else cout << ret[s][g] << endl;
  }
    return(0);
 
}

AOJ0204 UFO Shooting Down Operation

解法


当たり判定を間違えててWA連発してしまった。
レーザーの威力が出ない範囲内で当たるという
こんなケースがあったのが気づかなかった。気づけなかった。

ソース


#include<complex>
#include<algorithm>
#include<vector>
#include<map>
#include<iomanip>
#include<iostream>
#include<queue>
using namespace std;
#define fr first
#define sc second

struct line: public vector< complex<double> >{
  line(){};
  line( const complex<double>& a, const complex<double>& b){
    push_back(a);
    push_back(b);
  }
};
struct circle {
  complex<double> p; double r;
  circle():p(0,0),r(0){};
  circle(const complex<double> &p, double r) : p(p),r(r){}
};

typedef complex < double > P;
typedef line               L;
typedef pair < P, P >      Ls;
typedef vector< P >        G;
typedef vector< P >        Ps;
typedef vector< L >        LLL;
typedef circle             C;
const double EPS = 1e-9;
const double INF = 1e8;

bool   eq(P,P); //点:点 同一判定
double cross(P,P); //外積
double dot(P,P); //内積
int    ccw(P,P,P); //3点の位置関係
bool   parallel(L,L); // 直線//直線
bool   orthogonal(L,L); //直線⊥直線
bool   intersect(L,L); //線分:線分交差
bool   intersect(L,P); //線分:点交差
bool   intersect(Ls,Ls); //直線:直線交差
bool   intersect(Ls,L); //直線:線分交差
bool   intersect(Ls,P); //直線:点交差
int    intersect(C,L); //円:線分交点数
bool   intersect(C,Ls); //円:直線交差
bool   intersect(C,C); //円:円交差
bool   intersect(C,P); //円:点交差
double distance(L,L); //線分:線分の距離
double distance(L,P); //線分:点の距離
double distance(P,P); //点:点の距離
double distance(Ls,P); //直線:点距離
double distance(Ls,Ls); //直線:直線距離
double distance(Ls,L); //直線:線分距離
P      crosspoint(L,L); //線分:線分交点計算
L      crosspoint(C,Ls); //円:直線交点計算
L      crosspoint(C,L); //円:線分交点計算
L      crosspoint(C,C); //円:円交点計算
int    contains(G,P); //図形:点内包判定
double area2(G); //面積
bool   isconvex(G); //凸性判定
Ps     convex(G); //凸包

namespace std {
  bool operator < (const P& a, const P& b) {
    return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
  }
}
L llcomb(Ls a){
  L line( a.fr, a.sc);
  return line;
}
Ls llrcomb(L a){
  Ls line( a[0], a[1]);
  return line;
}
bool eq( P a, P b){ //OK
  return abs( a - b) < EPS;
}
double cross( P a,  P b){ //OK
  return imag( conj(a) * b);
}
double dot( P a, P b){ //OK
  return real( conj(a) * b);
}
P projection( L l, P p) { //OK
  double t = dot( p - l[0], l[0] - l[1]) / norm( l[0] - l[1]);
  return l[0] + t * ( l[0] - l[1]);
}
int ccw( P a, P b, P c){  //OK
  b -= a, c -= a;
  if(cross(b,c) > 0)    return +1;  // a → b で 反時計方向におれて c
  if(cross(b,c) < 0)    return -1; // a → b で 時計方向におれて c
  if(dot(b,c) < 0)      return +2;  // c -- a -- b
  if(norm(b) < norm(c)) return -2; // a -- b -- c
                        return 0;  // a -- c -- b
}
bool intersect( L a, L b){ //OK
  return ccw( a[0], a[1], b[0]) * ccw( a[0], a[1], b[1]) <= 0 &&
    ccw( b[0], b[1], a[0]) * ccw( b[0], b[1], a[1]) <= 0;
}
bool intersect( L a, P p){ //OK
   return abs( a[0] - p) + abs( a[1] - p) - abs( a[1] - a[0]) < EPS;
}
bool intersect( Ls l, Ls m) { //OK
  return abs(cross(l.sc-l.fr, m.sc-m.fr)) > EPS ||
         abs(cross(l.sc-l.fr, m.fr-l.fr)) < EPS;
}
bool intersect(Ls l, L s) { //OK
  return cross( l.sc - l.fr, s[0] - l.fr) *
         cross( l.sc - l.fr, s[1] - l.fr) < EPS;
}
bool intersect(Ls l, P p) { //OK
  return abs( cross( l.sc - p, l.fr - p)) < EPS;
}
bool intersect( C c, Ls s){ //OK
  return distance( s, c.p) <= c.r + EPS;
}
bool intersect( C a, C b){ //OK
  return ( norm( a.p - b.p) - ( a.r + b.r) * ( a.r + b.r) < EPS) &&
    ( norm( a.p - b.p) - ( a.r - b.r) * ( a.r - b.r) > -EPS);
}
int intersect( C c, L l){ //OK
  if( norm( projection( l, c.p) - c.p) - c.r * c.r > EPS) return 0;
  const double d1 = abs( c.p - l[0]), d2 = abs( c.p - l[1]);
  if( d1 < c.r + EPS && d2 < c.r + EPS) return 0;
  if( d1 < c.r - EPS && d2 > c.r + EPS
      || d1 > c.r + EPS && d2 < c.r - EPS ) return 1;
  const P h = projection( l, c.p);
  if( dot( l[0] - h, l[1] - h) < 0) return 2;
  return 0;
}
bool intersect( C c, P p){ //OK
  return abs( abs( p - c.p) - c.r ) < EPS;
}
double distance( L s, P p){ //OK
  P r = projection(s, p);
  if ( intersect( s, r)) return abs( r - p);
  return min( abs( s[0] - p), abs( s[1] - p));
}
double distance( L a, L b){ //OK
  if(intersect( a, b)) return 0;
  return min( min( distance( a, b[0]), distance( a, b[1])),
              min( distance( b, a[0]), distance( b, a[1])));
}
double distance( Ls l, P p) { //OK
  return abs(p - projection( llcomb(l), p));
}
double distance( Ls l, Ls m) { //OK
  return intersect( l, m) ? 0 : distance( l, m.fr);
}
double distance( Ls l, L s) { //OK
  if (intersect(l, s)) return 0;
  return min(distance(l, s[0]), distance(l, s[1]));
}
double distance( P a, P b){ //OK
  return abs( a - b);
}
bool parallel( L a, L b){
  return abs( cross( a[1] - a[0], b[1] - b[0])) < EPS;
}
bool orthogonal( L a, L b){
  return dot( a[0] - a[1], b[0] - b[1]) < EPS;
}
#define curr(P,i) P[i]
#define next(P,i) P[(i+1)%P.size()]
#define prev(P, i) P[(i+P.size()-1) % P.size()]
enum { OUT, ON, IN };
int conteins(G Q, P p){ //OK
  bool in = false;
  for(int i = 0 ; i < Q.size() ; i++ ){
    P a = curr(Q,i) - p, b = next(Q,i) - p;
    if(imag(a) > imag(b)) swap(a,b);
    if(imag(a) <= 0 && 0 < imag(b) && cross(a,b) < 0) in = !in;
    if(cross(a,b) == 0 && dot(a,b) <= 0) return ON;
  }
  return in ? IN : OUT;
}
double area2(G p){ //OK
  double A = 0;
  for (int i = 0; i < p.size(); ++i){
    A += cross(curr(p, i), next(p, i));
  }
  return A;
}
bool isconvex(G p) { // OK
  for (int i = 0; i < p.size(); ++i){
    if (ccw(prev(p, i), curr(p, i), next(p, i)) > 0) return false;
  }
  return true;
}
Ps convex(Ps ps) { //n>=3 OK
  int k = 0;
  sort(ps.begin(), ps.end());
  Ps ch(2 * ps.size());
  for (int i = 0; i < ps.size(); ch[k++] = ps[i++]){
    while (k >= 2 and ccw(ch[k-2], ch[k-1], ps[i]) <= 0) --k;
  }
  for (int i = ps.size()-2, t = k+1; i >= 0; ch[k++] = ps[i--]){
    while (k >= t and ccw(ch[k-2], ch[k-1], ps[i]) <= 0) --k;
  }
  ch.resize(k-1);
  return ch;
}
P crosspoint(L l, L m) { //OK
  double A = cross(l[1] - l[0], m[1] - m[0]);
  double B = cross(l[1] - l[0], l[1] - m[0]);
  if (abs(A) < EPS && abs(B) < EPS) return m[0]; // same line
  return m[0] + B / A * (m[1] - m[0]);
}
L crosspoint( C c, Ls l) { //OK
  const P hp = projection( llcomb(l), c.p), h =  hp - c.p;
  const double d2 = norm(h);
  P v = sqrt( c.r * c.r - d2) * ( l.sc - l.fr) / abs( l.sc - l.fr);
  return L(hp - v, hp + v);
}
L crosspoint( C c, L l) { //OK
  if(intersect(c, l) == 2) return crosspoint(c, llrcomb(l));
  L ret = crosspoint(c, llrcomb(l));
  if(dot(l[0] - ret[0], l[1] - ret[0]) < 0) ret[1] = ret[0];
  else ret[0] = ret[1];
  return ret;
}
L crosspoint(C c1, C c2){ //OK
  double d = abs(c1.p - c2.p);
  double s = (c1.r + c2.r + d) / 2;
  double S = sqrt( s * ( s - c1.r) * ( s - c2.r) * ( s - d));
  double h = 2 * S / d;
  P v = ( c2.p - c1.p) / ( abs( c2.p - c1.p));
  double m = sqrt( c1.r * c1.r - h * h);
  return L( c1.p + m * v + h * v * P(0,1), c1.p + m * v - h * v * P(0,1));
}

typedef pair< C, double > Cv;

int main(){

  int n;
  C c;
  c.p = P(0,0);

  while(cin >> c.r >> n, n){
    vector< Cv > ufo(n);
    for(int i = 0 ; i < n ; i++ ){
      double x, y, r, v;
      cin >> x >> y >> r >> v;
      ufo[i] = Cv( C( P( x, y), r), v);
    }

    int cnt = 0;
    while(!ufo.empty()){

      vector<Cv>::iterator mpos;
      double mini = INF;
      for(vector<Cv>::iterator it = ufo.begin() ; it != ufo.end() ; it++){
        double t =  abs((*it).fr.p) / (*it).sc;
        if( t >= 1.0 ) (*it).fr.p -= (*it).fr.p/abs((*it).fr.p) * (*it).sc;
        else (*it).fr.p = P(0,0);
        if(abs((*it).fr.p) <= c.r){
          cnt++;
          ufo.erase(it--);
        } else if( mini > abs((*it).fr.p) ){
          mini = abs((*it).fr.p);
          mpos = it;
        }
      }
      if(ufo.empty()) break;

      L l = L( c.p,(*mpos).fr.p * 2000.0);
      for(vector<Cv>::iterator it = ufo.begin() ; it != ufo.end() ; it++ ){
        if(intersect((*it).fr, l)){
          L p = crosspoint((*it).fr, l);
          if(abs(p[0]) > c.r || abs(p[1]) > c.r){ //あらら
            ufo.erase(it--);
          }
        }
      }
    }
    cout << cnt << endl;
  }
}


2014年1月21日火曜日

AOJ0562 JOI 国の買い物事情

解法


Dijkstraしてそれぞれの街のショッピングモールまでの最短距離を求めて、
なんといえばいいか、その…
例えば「A街」と「B街」がありました。
「A街」からショッピングモールまでの最短ルートが10でした。
「B街」から(ry の最短ルートは15でした。
これでA街とB街までの道の長さが10だったら、困るじゃん。
で多分これを計算で求める。
ルート = A + ( B - A ) + ( A~B - ( B - A ) ) / 2
なんか図を書いてみたらこうなった。
あとは切り上げ。
nで割るとしたら ( もとの数 + n - 1 ) / n で良い感じに切り上げできる。

ソース


#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
typedef pair < int , int > Pi;
#define fr first
#define sc second
#define INF ( 1 << 30 )
struct edge{
  int to, cost;
};
vector < edge > info[3001];
int main() {
  int N, M, K;
 
  cin >> N >> M >> K;
  for(int i = 0 ; i < M ; i++ ){
    int a, b, c;
    cin >> a >> b >> c;
    info[a].push_back((edge){ b, c});
    info[b].push_back((edge){ a, c});
  }
 
  int used[3001];
  fill_n( used, 3001, INF);
  priority_queue< Pi , vector< Pi >,greater< Pi > > que;
  for(int i = 0 ; i < K ; i++ ){
    int a;
    cin >> a;
 
    que.push(Pi( 0, a));
    used[a] = 0;
 
    while(!que.empty()){
      Pi p = que.top();
      que.pop();
      for(int j = 0 ; j < info[p.sc].size() ; j++ ){
        edge e = info[p.sc][j];
        if( used[e.to] > p.fr + e.cost ){
          used[e.to] = p.fr + e.cost;
          que.push( Pi( used[e.to], e.to));
        }
      }
    }
  }
 
 
  int ret = 0;
  for(int i = 1 ; i <= N ; i++ ){
    for(int j = 0 ; j < info[i].size() ; j++ ){
      if( used[i] <= used[info[i][j].to]){
        const int java = used[info[i][j].to] - used[i];
        ret = max( ret, used[i] + java + (info[i][j].cost - java + 1) / 2);
      }
    }
  }
  cout << ret << endl;
}

AOJ2219 THE BYDOLM@STER

解法


個数無限のナップザック×3。
名前は見た感じ不要。入力がめんどくさかった。

ソース


#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
using namespace std;
 
int main() {
  int N, M, cost[300], exp[300][3], dp[301];
  while(cin >> N >> M){
    for(int i = 0 ; i < N ; i++ ){
      string s;
      getline(cin, s), getline(cin, s);
      cin >> cost[i] >> exp[i][0] >> exp[i][1] >> exp[i][2];
    }
    int ret = 0;
    for(int i = 0 ; i < 3 ; i++ ){
      fill_n( dp, 301, 0);
      for(int j = 0 ; j < N ; j++ ){
        for(int k = 0 ; k <= M ; k++ ){
          if(k - cost[j] >= 0 ){
            dp[k] = max( dp[k], dp[k-cost[j]] + exp[j][i]);
            ret = max( ret, dp[k]);
          }
        }
      }
    }
    cout << ret << endl;
  }
}

2014年1月13日月曜日

AOJ0283 勉強会

解法


2分探索使ってほげると良い。
multisetとかmapとか色々使ったけどやっぱりvectorが実行時間が短かった。

ソース


#include<cstdio>
#include<algorithm>
#include<map>
#include<vector>
#include<string>
using namespace std;
 
#define INF ( 1 << 30 )
typedef pair < int , int > Pi;
 
int main()
{
  int N, Q;
  int stmp[1000000], comp[1000000], a;
  char buff[1024];
  scanf( "%d %d", &N, &Q);
  for(int i = 0 ; i < N ; i++ ){
    scanf( "%d", &stmp[i]);
    comp[i] = stmp[i];
  }
  sort( comp, comp + N);
 
  vector< int > sym;
  while(Q--){
    scanf("%s %d", buff, &a);
    if(*buff == 'A'){ //ADD
 
      sym.push_back(stmp[a - 1]);
      sort( sym.begin(), sym.end());
 
    } else if(*buff == 'R'){ //REMOVE
 
      sym.erase( lower_bound( sym.begin(), sym.end(), stmp[a - 1]));
 
    } else { //CHECK
 
      int left = 0, right = INF;
      while(left != right){
        int center = ( left + right ) / 2;
        int pre = 0, BAN = 0;
        for(int i = 0 ; i < sym.size() ; i++ ){
          int p = distance( comp,lower_bound( comp, comp + N, sym[i] - center));
          BAN += max( p - pre, 0);
          pre = distance( comp, upper_bound( comp, comp + N, sym[i]));
        }
        BAN += max( N - pre, 0);
        if(BAN <= a) right = center;
        else left = center + 1;
      }
      if( left != INF) printf("%d\n", left);
      else puts("NA");
 
    }
  }
  return false;
}

AOJ0041: Expression

問題概要


10パズル

解法


括弧とか括弧とかが面倒なので面倒くさいけど場合分けで書いた。
((a.b).(c.d))
(((a.b).c).d)
((a.(b.c)).d)
多分この3通りだと思う。

ソース


#include<iostream>
#include<algorithm>
#include<string>
#include<cstdio>
#include<cstdlib>
#include<sstream>
using namespace std;
#define rep(i,n) for(int i = 0 ; i < n ; i++ )
int d[4];
bool flg = false;
string s = "+-*";
int calc( int a, int op, int b){
  if( op == 0) return a + b;
  if( op == 1) return a - b;
  return a * b;
}
bool solve(int a, int b, int c){
  flg++;
  if(calc( calc( calc( d[0], a, d[1]), b, d[2]), c, d[3]) == 10){
    return printf("(((%d %c %d) %c %d) %c %d)\n", d[0], s[a], d[1], s[b], d[2], s[c], d[3]);
  }
  if(calc( calc( d[0], a, d[1]), b, calc( d[2], c, d[3])) == 10){
    return printf("((%d %c %d) %c (%d %c %d))\n", d[0], s[a], d[1], s[b], d[2], s[c], d[3]);
  }
  if(calc( calc( d[0], a, calc( d[1], b, d[2])), c, d[3]) == 10){
    return printf("((%d %c (%d %c %d)) %c %d)\n", d[0], s[a], d[1], s[b], d[2], s[c], d[3]);
  }
  return flg = false;
}
 
bool judge(){
  rep(i,3) rep(j,3) rep(k,3) if(solve( i, j, k)) return true;
}
int main(){
  while(flg = true){
    rep(i,4) cin >> d[i];
    if(!d[0] && !d[1] && !d[2] && !d[3]) break;
    sort(d, d + 4);
    do if(judge()) break; while(next_permutation(d,d+4));
    if(!flg) puts("0");
  }
}

2014年1月1日水曜日

AOJ0070 Combination of Number Sequences

解法


書いていて気持ちが良くなるメモ化再帰。
書いていて気持ちが良い(再掲)

ソース


#include<iostream>
#include<algorithm>
using namespace std;
int dp[10][1<<10][331], n; //nの制約は自明だけど sはどれくら(ry ← 331か
int rec( int now, int used,int sum){
  if( sum < 0 ) return 0;
  if( now == n ) return sum == 0;
  if(~dp[now][used][sum]) return dp[now][used][sum];
  int ret = 0;
  for(int i = 0 ; i < 10 ; i++ ){
    if((used >> i) & 1)
      ret += rec( now + 1, used&~(1 << i), sum - i * (now + 1));
  }
  return dp[now][used][sum] = ret;
}
int main(){
  int s;
  while(cin >> n >> s){
    fill_n( **dp, 10 * (1 << 10) * 331, -1);
    cout << rec( 0, (1 << 10) - 1, s) << endl;
  }
}