SRM602 div2 Med PilingRectsDiv2

問題読み間違えて詰んでた

問題概要

・幅Xi高さYiの長方形がN個ある
・面積がlimit以上となるように長方形を重ねる(はみ出して良い、はみ出したらいけないと思っていた)
・90度回転して良い
・最大で何枚重ねられるか

方針

まず幅>高さとなるようにし、幅で昇順に並び替える。重ねる長方形の最小の幅を固定し重ねた時にlimitを超えるかどうか調べる。超えるなら重ねる。

最小の幅がO(N)。それぞれの最小の幅について幅が最小の幅以上の長方形についてlimitを超えるかどうかの計算でO(N)。よって計算量はO(N2)。

コード

typedef pair<int, int> P;
class PilingRectsDiv2 {
public:
  int getmax(vector <int> X, vector <int> Y, int limit) {
    int n = X.size();
    vector<P> v(n);
    FOR(i,0,n) {
      if(X[i] < Y[i]) swap(X[i], Y[i]);
      v[i] = P(X[i], Y[i]);
    }
    sort(v.begin(), v.end());
    int ans = -1;
    FOR(i,0,n) {
      int cnt = 0;
      FOR(j,i,n) if(v[i].first * min(v[i].second, v[j].second) >= limit) cnt++;
      if(cnt) ans = max(ans, cnt);
    }
    return ans;
  }
};

英語難しい

SRM601 div2 Med WinterAndCandies

問題概要

・i番目のキャンディーのタイプはa_i

・タイプが1,2,3...,Kまで1つずつになるようにキャンディーを選ぶ選び方は何通りか

方針

・K = 1の時

1の個数

・K = 2の時

1の個数×2の個数

・K = xの時

1の個数×2の個数×...×xの個数

となるのでこれらを全て足した値が答え。

コード

class WinterAndCandies {
  public:
    int getNumber(vector <int> type) {
      int ret = 0;
      int num[51]; CLR(num);
      FOR(i,0,(int)type.size()) {
        num[type[i]]++;
      }
      int t = 1;
      FOR(i,1,51) {
        t *= num[i];
        ret += t;
      }
      return ret;
    }
};

SRM600div2 Med ORSolitaireDiv2

今日からSRMdiv2med埋め開始(atcoderレート1469)

TopCoder Statistics - Match Overview

例えばgoal = 00101110の時、goalのbitが0となっている桁が1になっている数字は取り除く必要はない。 10001111は取り除く必要なし。00101000は取り除く可能性がある。 取り除く可能性がある数字の集合からgoalを作れないようにするには最小で何個の数字を取り除けば良いかという問題。

集合の数字にについて、桁ごとに1が立っている数字が何個あるか調べて、その最小値を答えれば良い。

class ORSolitaireDiv2{
  public: int getMinimum(vector <int> numbers, int goal) {
    int n = numbers.size();
    int ret = 1e9;
    int bit[30]; CLR(bit);
    FOR(i,0,n) {
      bool ok = true;
      FOR(j,0,30) {
        if((numbers[i]>>j)&1 && !((goal>>j)&1)) ok = false;
      }
      if(!ok) continue;
      FOR(j,0,30) {
        if((numbers[i]>>j)&1) bit[j]++;
      }
    }
    FOR(j,0,30) if((goal>>j)&1) ret = min(ret, bit[j]);
    return ret;
  }

ディスカバリーチャンネルコードコンテスト2016 C - ロト2

できなかったのでやり直し。

C: ロト2 - DISCO presents ディスカバリーチャンネル コードコンテスト2016 予選 | AtCoder

x * y が kの倍数 <=> gcd(x, k) * gcd(y, k) が kの倍数という性質を用いる。

計算量はO(N2) -> O(Kの約数の個数2)になる。

今回Kの約数は1344個らしい。

gcd(Ai, K)の値をmapに保存しておいて、Kの倍数になるか2重ループで調べる。 gcd(Ai, K) * gcd(Aj, K) % K == 0となる時、 map[gcd(Ai, K)] == map[gcd(Aj, K)] の時はmap[gcd(Ai, K)]個から2個選ぶ選び方の数、 そうでない時はmap[gcd(Ai, K)] * map[gcd(Aj, K)]。 ただし、二重ループで重複して数えてしまうので最後に2で割って足した 。

#include <algorithm>
#include <cstdio>
#include <iostream>
#include <map>
#include <cmath>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <vector>
#include <stdlib.h>
#include <stdio.h>
#include <bitset>
#include <cstring>
using namespace std;
#define FOR(I,A,B) for(int I = (A); I < (B); ++I)
#define CLR(mat) memset(mat, 0, sizeof(mat))
typedef long long ll;
//最大公約数
ll gcd(ll a, ll b) {
  while (a && b) {
    if (a >= b) a %= b;
    else b %= a;
  }
  return a + b;
}
int main()
{
  ios::sync_with_stdio(false);
  cin.tie(0);
  ll N, K; cin >> N >> K;
  map<ll, ll> MAP;
  FOR(i,0,N) {
    ll in; cin >> in;
    MAP[gcd(K, in)]++;
  }
  ll ans = 0;
  ll ans2 = 0;
  for(auto m1 : MAP) {
    for(auto m2 : MAP) {
      if((m1.first * m2.first) % K == 0) {
        if(m1.first != m2.first) {
          ans2 += m1.second * m2.second;
        } else {
          ans += m1.second * (m2.second - 1) / 2;
        }
      }
    }
  }
  cout << ans + ans2 / 2 << endl;
  return 0;
}

ABC070 参加記録

ABCしかなかったのでABC070に参加しました。

100-200-300-400なので全完できた。

A - Palindromic Number

やるだけ。

int main()
{
  string s;
  cin >> s;
  if(s[0] == s[2]) {
    puts("Yes");
  } else {
    puts("No");
  }
  return 0;
}

B - Two Switches

場合分けしまくればO(1)でできるんだろうけどめんどくさいのでいもす法ぽくやった0(N)。

#define FOR(I,A,B) for(int I = (A); I < (B); ++I)
int main()
{
  int a,b,c,d;
  cin >> a >> b >> c >> d;
  int sw[111]; FOR(i,0,111) sw[i] = 0;
  sw[a]++;sw[b]--;sw[c]++;sw[d]--;
  FOR(i,1,111) sw[i] += sw[i-1];
  int ans = 0;
  FOR(i,0,111) if(sw[i] == 2) ans++;
  cout << ans << endl;
  return 0;
}

C - Multiple Clocks

次に全ての針が上むきで揃うのは全ての針の周期の最小公倍数秒後になる。

最小公倍数求めるライブラリ作っておくと良い。

#define FOR(I,A,B) for(int I = (A); I < (B); ++I)
typedef long long ll;
//最大公約数
ll gcd(ll a, ll b) {
  while (a && b) {
    if (a >= b) a %= b;
    else b %= a;
  }
  return a + b;
}
//最小公倍数
ll lcm(ll a, ll b) { return (a / gcd(a, b)) * b;}
int main()
{
  int N; cin >> N;
  ll ans = 1;
  FOR(i,0,N) {
    ll in; cin >> in;
    ans = lcm(ans, in);
  }
  cout << ans << endl;
  return 0;
}

D - Transit Tree Path

絶対にKを経由するのでKからそれぞれの頂点iまでの最短距離d[i]を求めておいてd[x]+d[y]を出力すればOK。

今回のグラフは木なので最短距離を求めるのはdfsでもダイクストラでもどっちでも良さそう。

#define FOR(I,A,B) for(int I = (A); I < (B); ++I)
typedef long long ll;
typedef pair<ll, ll> P;
const ll inf = 1e15;
struct edge{
  ll to, cost;
  edge(ll t, ll c) {
    to = t, cost = c;
  }
};
// Kからの距離を求めておく
int N;
vector<edge> G[100005];
ll d[100005];
void dijkstra(int s){
  priority_queue<P, vector<P>, greater<P> >que;
  FOR(i,1,N+1) d[i] = inf;
  d[s] = 0;
  que.push(P(0, s));
  while(!que.empty()){
    P p = que.top(); que.pop();
    int v = p.second;
    if(d[v] < p.first) continue;
    for(auto &e : G[v]){
      if(d[e.to] > d[v] + e.cost){
        d[e.to] = d[v] + e.cost;
        que.push(P(d[e.to], e.to));
      }
    }
  }
}
int main()
{
  cin >> N;
  FOR(i,0,N-1) {
    ll a, b, c;
    cin >> a >> b >> c;
    G[a].push_back(edge(b, c));
    G[b].push_back(edge(a, c));
  }
  int Q, K; cin >> Q >> K;
  // Kからの距離
  dijkstra(K);
  FOR(i,0,Q) {
    int x, y; cin >> x >> y;
    cout << d[x] + d[y] << endl;
  }
  return 0;
}

yukicoder 171 参加記録

yukicoder 171に参加しました。

5/6完で45位でした。

星3のDPが解けなかった。

No.552 十分簡単な星1の問題

long long でもオーバーフローするのでstringで受け取って+“0"する。

ただし、0が入力される場合はそのまま出力することに注意。

#define FOR(I,A,B) for(int I = (A); I < (B); ++I)
#define CLR(mat) memset(mat, 0, sizeof(mat))
typedef long long ll;
int main()
{
  string s;
  cin >> s;
  if(s.length() == 1 && s[0] == '0') cout << 0 << endl;
  else cout << s << 0 << endl;
  return 0;
}

No.553 AlphaCoder Rating

やるだけだけど数式が複雑でめんどくさそうなので後回しにした。

誤差±1までOKなので誤差を気にせず実装して大丈夫だった。

逆関数の知識が必要。

#define FOR(I,A,B) for(int I = (A); I < (B); ++I)
#define CLR(mat) memset(mat, 0, sizeof(mat))
typedef long long ll;
int main()
{
  int N; cin >> N;
  double r[N];
  FOR(i,0,N) cin >> r[i];
  double Fn, fn, f1, finf;
  FOR(i,1,N+1) Fn += pow(0.81, i);
  Fn = sqrt(Fn);
  double tmp = 0;
  FOR(i,1,N+1) tmp += pow(0.9, i);
  Fn /= tmp;
  f1 = sqrt(0.81) / 0.9;
  finf = sqrt(0.81 / 0.19) / (0.9 / 0.1);
  fn = (Fn - finf) / (f1 - finf) * 1200;
  double ans = 0;
  FOR(i,1,N+1) {
    ans += pow(2, r[i-1] / 800.0) * pow(0.9, i);
  }
  ans /= tmp;
  ans = 800 * log(ans) / log(2);
  ans -= fn;
  cout << int(ans) << endl;
  return 0;
}

No.554 recurrence formula

第2項から順に求めていく。

和の部分を毎回求めていたらO(n2)となるのでTLE。

累積和を保存しておけばO(n)となってAC。

#define FOR(I,A,B) for(int I = (A); I < (B); ++I)
#define CLR(mat) memset(mat, 0, sizeof(mat))
typedef long long ll;
const ll mod = 1e9 + 7;
int main()
{
  int n; cin >> n;
  ll oddsum = 1, evensum = 0;
  ll a = 1;
  FOR(i,2,n+1) {
    if(i % 2 == 0) {
      a = i * oddsum;
      a %= mod;
      evensum += a;
      evensum %= mod;
    } else {
      a = i * evensum;
      a %= mod;
      oddsum += a;
      oddsum %= mod;
    }
  }
  cout << a % mod << endl;
  return 0;
}

No.555 世界史のレポート

DPぽいなと思ったけどできなかった問題。

dp[i] := 長さをi以上にするのに必要な最小コストとしてしまうとO(n2)となりTLE。

dp[i] := 長さをちょうどiにするのに必要な最小コストとする。 長さをiにするには、長さがiの約数dになった時にコピーしてペーストを(i - d) / d回する。 iの約数の個数は高々{ 2\sqrt n } らしいのでO({ n\sqrt n })となりAC。

長さがn-1の時にコピーしてペースとしたら2n-2になるので、dp[2n-2]まで計算する。

#define FOR(I,A,B) for(int I = (A); I < (B); ++I)
#define CLR(mat) memset(mat, 0, sizeof(mat))
typedef long long ll;

int main()
{
  int N, C, V; cin >> N >> C >> V;
  ll dp[2*N]; FOR(i,0,2*N) dp[i] = 1e9;
  dp[0] = dp[1] = 0;
  // ちょうどiにする
  FOR(i, 1, 2*N) {
    // Aの個数がiの約数dになったらコピーしてそのあとペースト
    // (i / d - 1) 回足せばちょうどiになる
    for(int d = 1; d * d <= i; d++) {
      if(i % d == 0) {
        dp[i] = min(dp[i], dp[d] + C + V * (i / d - 1));
        dp[i] = min(dp[i], dp[i/d] + C + V * (d - 1));
      }
    }
  }
  ll ans = dp[N];
  FOR(i, N, 2 * N) ans = min(ans, dp[i]);
  cout << ans << endl;
  return 0;
}

No.556 仁義なきサルたち

Union-Findを使う。子分の数を保存しておく。

xとyが喧嘩したらxとyを同じグループにする。この時子分の数が多い方を親とする。 子分の数が同じ時はx<yならxを親にする。x>yならyを親にする。

#define FOR(I,A,B) for(int I = (A); I < (B); ++I)
#define CLR(mat) memset(mat, 0, sizeof(mat))
typedef long long ll;
// union - find tree !!!!!!!!!!!!!!!!!!!!!!!!!
vector<int> par; //oya
vector<int> rnk; //子分の数
// n要素で初期化
void init(int n){
    par.resize(n);rnk.resize(n);
    FOR(i, 0, n){par[i] = i;rnk[i] = 1;}
}
//木の根を求める
int find(int x){
    if(par[x] == x) return x;
    else return par[x] = find(par[x]);
}
//xとyの属する集合を併合
void unite(int x, int y){
    x = find(x);y = find(y);
    if(x == y) return;
    if(rnk[x] < rnk[y]) swap(x, y);
    if(rnk[x] == rnk[y] && x > y) swap(x, y);
    par[y] = x;
    rnk[x] += rnk[y];
    rnk[y] = 0;
    return;
}
int main()
{
  int N, M;
  cin >> N >> M;
  init(N+1);
  FOR(i,0,M) {
    int a, b; cin >> a >> b;
    unite(a, b);
  }
  FOR(i,1,N+1) {
    cout << find(i) << endl;
  }
  return 0;
}

No.557 点対称

それぞれの桁に何通りの数字がありえるのか考える。

そして全てかける。

ただし、最大で{ 5^{10^{18}} }くらいの計算をする必要が出てくるのでTLEに注意。

高速に(O(log n))累乗を計算するテクニックを使う必要がある。

例えば、aの8乗を計算する時はaを8回かけるよりa->a×a->(a2)×(a2)->(a4)×(a4)というように掛け算した結果を使用した方が早い。a ×= aを3回計算すれば終わる。 100乗の場合100 = 64(26) + 32(25) + 4(22)であり、a ×= aを5回計算すれば終わる。100を2進数にした時に右のbitから調べていき1になっている時にaを足せば良い。

#define FOR(I,A,B) for(int I = (A); I < (B); ++I)
#define CLR(mat) memset(mat, 0, sizeof(mat))
typedef long long ll;
const int mod = 1e9 + 7;
int main()
{
  ll N; cin >> N;
  if(N == 1) {
    cout << 2 << endl;
    return 0;
  }
  ll ans;
  if(N % 2 == 1) ans = 3;
  else ans = 1;
  // 5^(N/2-1)を高速に計算
  ll j = 0;
  ll fi = 5;
  ll p = N / 2 - 1;
  while((1LL<<j) <= p) {
    if((p>>j)&1) {
      ans *= fi;
      ans %= mod;
    }
    fi *= fi;
    fi %= mod;
    j++;
  }
  ans *= 4;
  cout << ans % mod << endl;
}

問題集(随時更新)

雑なので時間があったらまとめていこう...

全探索(工夫して全探索も)

http://arc020.contest.atcoder.jp/tasks/arc020_2

https://www.hackerrank.com/challenges/two-characters

http://poj.org/problem?id=3279

http://abc002.contest.atcoder.jp/tasks/abc002_4

http://arc074.contest.atcoder.jp/tasks/arc074_b

深さ優先全探索dfs

http://arc001.contest.atcoder.jp/tasks/arc001_3

http://arc009.contest.atcoder.jp/tasks/arc009_3

メモ化再帰

http://tenka1-2012-final.contest.atcoder.jp/tasks/tenka1_2012_final_a

http://wupc2nd.contest.atcoder.jp/tasks/wupc_02

幅優先全探索

http://arc005.contest.atcoder.jp/tasks/arc005_3

http://arc001.contest.atcoder.jp/tasks/arc001_2

https://www.hackerrank.com/contests/w32/challenges/circular-walk

動的計画法dp

http://wupc2nd.contest.atcoder.jp/tasks/wupc_02

http://abc054.contest.atcoder.jp/tasks/abc054_d

https://www.hackerrank.com/contests/world-codesprint-10/challenges/permutation-happiness

bit

http://arc007.contest.atcoder.jp/tasks/arc007_3

bit , nCrの計算

https://www.hackerrank.com/contests/world-codesprint-10/challenges/maximal-and-subsequences

bit+dp

http://arc010.contest.atcoder.jp/tasks/arc010_3

メモ化再帰+dp+bit???!!! - > 再帰関数の中にdp...

https://www.hackerrank.com/contests/rookierank-3/challenges/max-score

貪欲法

http://arc006.contest.atcoder.jp/tasks/arc006_3

http://abc003.contest.atcoder.jp/tasks/abc003_3

ベルマンフォード法

http://abc061.contest.atcoder.jp/tasks/abc061_d

Union-Find tree

http://poj.org/problem?id=1182

クラスカル

http://poj.org/problem?id=3723

しゃくとり法

http://abc038.contest.atcoder.jp/tasks/abc038_c

http://abc032.contest.atcoder.jp/tasks/abc032_c

http://poj.org/problem?id=3061

累積和

http://abc037.contest.atcoder.jp/tasks/abc037_c

二次元累積和

http://agc015.contest.atcoder.jp/tasks/agc015_c

クラスカル法, 自作の評価関数でsort, 最小公倍数, 平均最大化with二分探索

https://www.hackerrank.com/contests/w31/challenges/spanning-tree-fraction

関数の最大化最小化with二分探索

http://poj.org/problem?id=1064

http://poj.org/problem?id=2456

https://www.codechef.com/SNCKPA17/problems/CONSESNK

http://arc075.contest.atcoder.jp/tasks/arc075_b

stack (使う必要ないやつもある)

https://www.hackerrank.com/challenges/reduced-string

https://www.hackerrank.com/challenges/counting-valleys

いもす法

http://abc001.contest.atcoder.jp/tasks/abc001_4

半分全列挙

http://poj.org/problem?id=2785

強連結成分分解, トポロジーソート??!!, bitset

https://www.hackerrank.com/contests/world-codesprint-11/challenges/hackerland

BIT

+圧縮

http://arc075.contest.atcoder.jp/tasks/arc075_c

桁DP

http://abc007.contest.atcoder.jp/tasks/abc007_4

http://abc029.contest.atcoder.jp/tasks/abc029_d

https://yukicoder.me/problems/no/220

https://yukicoder.me/problems/no/189

行列累乗

木DP

https://arena.topcoder.com/#/u/practiceCode/17090/60726/14812/2/331054

最小カット

グラフ

http://abc040.contest.atcoder.jp/tasks/abc040_d

ゲーム(3ターン目以降でいい点取れないので実質1ターンで終わる問題)

https://community.topcoder.com/tc?module=ProblemDetail&rd=15836&pm=12946 https://beta.atcoder.jp/contests/arc085/tasks/arc085_b