提出 #75052257


ソースコード 拡げる

#include <atcoder/all>
#include <bits/stdc++.h>

using namespace std;
using namespace atcoder;

// 型・定数
using ll = long long;
const ll INFLL = 4e18;
const int INF = 2100000000;
const ll MOD = 1000000007;
using mint = modint1000000007; // 998244353 の場合は modint998244353 に変更
const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};

// マクロ
#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define all(p) p.begin(), p.end()
#define yes cout << "Yes\n"
#define no cout << "No\n"
#define fi first
#define se second

// 優先度付きキュー(最小値取り出し)
template <class T> using _pq = priority_queue<T, vector<T>, greater<T>>;

// 下限・上限探索
template <class T> int LB(const vector<T> &v, const T &a) {
  return lower_bound(all(v), a) - v.begin();
}
template <class T> int UB(const vector<T> &v, const T &a) {
  return upper_bound(all(v), a) - v.begin();
}

// 条件付き更新
template <class T> bool chmin(T &a, T b) {
  if (b < a) {
    a = b;
    return true;
  } else
    return false;
}
template <class T> bool chmax(T &a, T b) {
  if (a < b) {
    a = b;
    return true;
  } else
    return false;
}

// ソート
template <class T> void So(vector<T> &v) { sort(all(v)); }
template <class T> void Sore(vector<T> &v) { sort(all(v), greater<T>()); }

// Yes/No 出力
bool yneos(bool a, bool upp = false) {
  cout << (a ? (upp ? "YES\n" : "Yes\n") : (upp ? "NO\n" : "No\n"));
  return a;
}

// ベクタ系の補助関数
template <class T> void vec_out(const vector<T> &p, int ty = 0) {
  if (ty == 2) {
    cout << '{';
    for (size_t i = 0; i < p.size(); i++) {
      if (i)
        cout << ",";
      cout << '"' << p[i] << '"';
    }
    cout << "}\n";
  } else {
    if (ty == 1)
      cout << p.size() << "\n";
    for (size_t i = 0; i < p.size(); i++) {
      if (i)
        cout << " ";
      cout << p[i];
    }
    cout << "\n";
  }
}

template <class T> T vec_min(const vector<T> &a) {
  assert(!a.empty());
  T ans = a[0];
  for (const auto &x : a)
    chmin(ans, x);
  return ans;
}
template <class T> T vec_max(const vector<T> &a) {
  assert(!a.empty());
  T ans = a[0];
  for (const auto &x : a)
    chmax(ans, x);
  return ans;
}
template <class T> T vec_sum(const vector<T> &a) {
  T ans = T(0);
  for (const auto &x : a)
    ans += x;
  return ans;
}
template <class T> vector<T> cumsum(const vector<T> &v) {
  vector<T> res(v.size() + 1, 0);
  rep(i, 0, v.size()) res[i + 1] = res[i] + v[i];
  return res;
}

int pop_count(ll a) { return __builtin_popcountll(a); }
template <class T> T square(T a) { return a * a; }
template <class T> vector<int> compress(vector<T> &v) {
  vector<T> tmp = v;
  sort(all(tmp));
  tmp.erase(unique(all(tmp)), tmp.end());
  vector<int> res(v.size());
  rep(i, 0, v.size()) res[i] = LB(tmp, v[i]);
  return res;
}

/* RollingHash (任意文字対応) */
// 使い方: RollingHash rh(s);
// rh.get(l, r): [l, r) のハッシュ値(pair)を取得
// rh.same(l1, r1, l2, r2): [l1, r1) と [l2, r2) が一致するか判定
struct RollingHash {
  using ull = unsigned long long;
  const ll base = 1007, mod1 = 1000000007, mod2 = 1000000009;
  vector<ll> pow1, pow2, hash1, hash2;
  RollingHash(const string &s) {
    int n = s.size();
    pow1.assign(n + 1, 1);
    pow2.assign(n + 1, 1);
    hash1.assign(n + 1, 0);
    hash2.assign(n + 1, 0);
    rep(i, 0, n) {
      pow1[i + 1] = (pow1[i] * base) % mod1;
      pow2[i + 1] = (pow2[i] * base) % mod2;
      int c = (unsigned char)s[i];
      hash1[i + 1] = (hash1[i] * base + c) % mod1;
      hash2[i + 1] = (hash2[i] * base + c) % mod2;
    }
  }
  pair<ll, ll> get(int l, int r) const {
    ll x1 = (hash1[r] - hash1[l] * pow1[r - l]) % mod1,
       x2 = (hash2[r] - hash2[l] * pow2[r - l]) % mod2;
    if (x1 < 0)
      x1 += mod1;
    if (x2 < 0)
      x2 += mod2;
    return {x1, x2};
  }
  bool same(int l1, int r1, int l2, int r2) const {
    return get(l1, r1) == get(l2, r2);
  }
};

/* エラトステネスの篩 (O(1)素数判定, 高速素因数分解) */
// 使い方: Sieve si(n); (nは最大値)
// si.is_prime(x): xが素数か判定
// si.factorize(x): xの素因数を1次元配列で返す (例: 12 -> {2, 2, 3})
// si.factorize_pair(x): 素因数をpairで返す (例: 12 -> {{2, 2}, {3, 1}})
// si.count_distinct(x): 異なる素因数の個数 ω(x) を返す (例: 12 -> 2)
struct Sieve {
  int max_n;
  vector<int> spf;
  Sieve(int n) : max_n(n), spf(n + 1) {
    for (int i = 0; i <= n; i++)
      spf[i] = i;
    for (int i = 2; i * i <= n; i++)
      if (spf[i] == i)
        for (int j = i * i; j <= n; j += i)
          if (spf[j] == j)
            spf[j] = i;
  }
  vector<int> factorize(int n) {
    vector<int> res;
    while (n != 1) {
      res.push_back(spf[n]);
      n /= spf[n];
    }
    return res;
  }
  vector<pair<int, int>> factorize_pair(int n) {
    vector<pair<int, int>> res;
    while (n != 1) {
      int p = spf[n];
      int count = 0;
      while (spf[n] == p) {
        count++;
        n /= p;
      }
      res.push_back({p, count});
    }
    return res;
  }
  bool is_prime(int n) {
    if (n <= 1)
      return false;
    return spf[n] == n;
  }
  int count_distinct(int n) {
    int cnt = 0;
    while (n != 1) {
      int p = spf[n];
      cnt++;
      while (spf[n] == p)
        n /= p;
    }
    return cnt;
  }
};

/* 約数全列挙 O(√N) / ソート済 */
vector<ll> get_divisors(ll n) {
  vector<ll> res;
  for (ll i = 1; i * i <= n; i++) {
    if (n % i == 0) {
      res.push_back(i);
      if (i * i != n)
        res.push_back(n / i);
    }
  }
  sort(all(res));
  return res;
}

/* 素因数分解 O(√N) */
vector<pair<ll, ll>> prime_factorize(ll n) {
  vector<pair<ll, ll>> res;
  for (ll a = 2; a * a <= n; a++) {
    if (n % a != 0)
      continue;
    ll ex = 0;
    while (n % a == 0) {
      ex++;
      n /= a;
    }
    res.push_back({a, ex});
  }
  if (n != 1)
    res.push_back({n, 1});
  return res;
}

/* LIS (最長増加部分列) O(N log N) / 復元可能 / 任意比較対応 */
// 使い方: LIS<T> lis;
// lis.build(v): LIS の長さを返す (デフォルトは狭義増加; strict=false で広義)
// lis.restore(): LIS の列を1つ返す
template <class T> struct LIS {
  vector<T> dp;
  vector<int> idx;
  vector<int> prev_;
  int build(const vector<T> &v, bool strict = true) {
    int n = v.size();
    dp.clear();
    idx.resize(n);
    prev_.assign(n, -1);
    for (int i = 0; i < n; i++) {
      int pos;
      if (strict)
        pos = lower_bound(dp.begin(), dp.end(), v[i]) - dp.begin();
      else
        pos = upper_bound(dp.begin(), dp.end(), v[i]) - dp.begin();
      if (pos == (int)dp.size())
        dp.push_back(v[i]);
      else
        dp[pos] = v[i];
      idx[i] = pos;
    }
    return dp.size();
  }
  vector<T> restore(const vector<T> &v) {
    int n = v.size(), len = dp.size(), cur = len - 1;
    vector<T> res;
    for (int i = n - 1; i >= 0 && cur >= 0; i--)
      if (idx[i] == cur) {
        res.push_back(v[i]);
        cur--;
      }
    reverse(res.begin(), res.end());
    return res;
  }
};

/* bfs_farthest (木の直径など / 非再帰展開) */
// auto p1 = bfs_farthest(G, 0);         // 頂点0から一番遠い点 {距離, 頂点}
// auto p2 = bfs_farthest(G, p1.second); // p1.secondから一番遠い点
// int diameter = p2.first;              // それが木の直径!
pair<int, int> bfs_farthest(const vector<vector<int>> &G, int start) {
  vector<int> dist(G.size(), -1);
  queue<int> q;
  q.push(start);
  dist[start] = 0;
  pair<int, int> res = {0, start};
  while (!q.empty()) {
    int v = q.front();
    q.pop();
    if (dist[v] > res.first)
      res = {dist[v], v};
    for (int to : G[v])
      if (dist[to] == -1) {
        dist[to] = dist[v] + 1;
        q.push(to);
      }
  }
  return res;
}

/* LCA (最小共通祖先) ダブリング */
// 使い方: LCA lc(G, 0); (0は根とする頂点)
// lc.get(u, v): uとvの最小共通祖先の頂点番号
// lc.dist(u, v): uとvの距離(エッジ数)
// lc.jump(v, k): 頂点vから親方向へk回遡った頂点(存在しなければ-1)
struct LCA {
  int n, ln;
  vector<vector<int>> parent;
  vector<int> depth;
  LCA(const vector<vector<int>> &G, int root = 0) {
    n = G.size();
    ln = 0;
    while ((1 << ln) <= n)
      ln++;
    parent.assign(ln, vector<int>(n, -1));
    depth.assign(n, 0);
    init(G, root);
    for (int k = 0; k + 1 < ln; k++)
      for (int v = 0; v < n; v++)
        if (parent[k][v] != -1)
          parent[k + 1][v] = parent[k][parent[k][v]];
  }
  void init(const vector<vector<int>> &G, int root) {
    queue<int> q;
    q.push(root);
    parent[0][root] = -1;
    depth[root] = 0;
    while (!q.empty()) {
      int v = q.front();
      q.pop();
      for (auto to : G[v])
        if (to != parent[0][v]) {
          parent[0][to] = v;
          depth[to] = depth[v] + 1;
          q.push(to);
        }
    }
  }
  int get(int u, int v) {
    if (depth[u] > depth[v])
      swap(u, v);
    for (int k = 0; k < ln; k++)
      if ((depth[v] - depth[u]) >> k & 1)
        v = parent[k][v];
    if (u == v)
      return u;
    for (int k = ln - 1; k >= 0; k--)
      if (parent[k][u] != parent[k][v]) {
        u = parent[k][u];
        v = parent[k][v];
      }
    return parent[0][u];
  }
  int dist(int u, int v) { return depth[u] + depth[v] - 2 * depth[get(u, v)]; }
  int jump(int v, int k) {
    for (int i = 0; i < ln; i++)
      if (k >> i & 1) {
        v = parent[i][v];
        if (v == -1)
          break;
      }
    return v;
  }
};

/* 組み合わせ計算 */
const int MAX = 200000;
ll fact[MAX + 1], invfact[MAX + 1];
ll mod_pow(ll a, ll b) {
  ll res = 1;
  a %= MOD;
  while (b) {
    if (b & 1)
      res = (res * a) % MOD;
    a = (a * a) % MOD;
    b >>= 1;
  }
  return res;
}
ll mod_inv(ll a) { return mod_pow(a, MOD - 2); }
void init_fact() {
  fact[0] = 1;
  rep(i, 1, MAX + 1) fact[i] = fact[i - 1] * i % MOD;
  invfact[MAX] = mod_inv(fact[MAX]);
  for (int i = MAX; i >= 1; i--)
    invfact[i - 1] = invfact[i] * i % MOD;
}
ll nCr(int n, int r) {
  if (r < 0 || r > n)
    return 0;
  return fact[n] * invfact[r] % MOD * invfact[n - r] % MOD;
}
// 差がk以上となるようにm個のボールを選ぶ方法は何通りか
// 結論から書くと、n-(k-1)*(m-1)Cm通りです。
// 最大公約数gcd・最小公倍数lcm
// ==========================================================

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  int n;
  cin >> n;
  // ▼ ライブラリの初期化 (アンコメントして使用)
  // dsu d(n);                               /* 1. dsu (UnionFind) */
  // fenwick_tree<ll> fw(n);                 /* 2. BIT */
  // mf_graph<ll> graph(n);                  /* 3. Dinic (最大流) */
  // scc_graph g(n);                         /* 4. SCC (強連結成分分解) */
  // lazy_segtree<S,op,e,F,mapping,comp,id> seg(n); /* 5. 遅延セグ木 */
  // Sieve si(n);                            /* 6. エラトステネスの篩 */
  // RollingHash rh(s);                      /* 7. ローリングハッシュ (要文字列s) */
  // LCA lc(G, 0);                           /* 8. 最小共通祖先 (ダブリング) */
  // init_fact();                            /* 9. 組み合わせ計算 (nCr用事前計算) */
  // vector<int> c_v = compress(v);          /* 10. 座標圧縮 */
  // LIS<int> lis; int len=lis.build(v); auto seq=lis.restore(v); /* 11. LIS */
  int m; cin >> m;
  vector<int> f(n);
  rep(i, 0, n) cin >> f[i];

  set<int> s(f.begin(), f.end());
  yneos((int)s.size() == n);
  yneos((int)s.size() == m);

  return 0;
}

/*
【 AtCoder Library (ACL) 使い方メモ 】

1. dsu (UnionFind)
   dsu d(n);            // n頂点で初期化
   d.merge(a, b);       // aとbを結合
   if (d.same(a, b))    // aとbが同じグループか判定
   int s = d.size(a);   // aが属するグループのサイズ
   int l = d.leader(a); // aの親(代表元)を取得

2. fenwick_tree (BIT) ※0-indexed注意!
   fenwick_tree<ll> fw(n); // 要素数nで初期化
   fw.add(p, x);           // p番目(0-indexed)にxを加算
   ll s = fw.sum(l, r);    // [l, r) の和を取得

3. segtree (セグメント木)
   segtree<int, op, e> seg(n);
   seg.set(p, x);          // p番目をxに変更
   int m = seg.prod(l, r); // [l, r) の結果を取得

   // ▼ よく使う op と e の組み合わせ
   // 【最大値】 int op(int a, int b) { return max(a, b); } / int e() { return
-1e9; }
   // 【最小値】 int op(int a, int b) { return min(a, b); } / int e() { return
1e9; }
   // 【区間和】 ll op(ll a, ll b) { return a + b; }       / ll e() { return 0;
}
   // 【 XOR 】 int op(int a, int b) { return a ^ b; }     / int e() { return 0;
}

4. lazy_segtree (遅延評価セグメント木)
   lazy_segtree<S, op, e, F, mapping, composition, id> seg(n);
   seg.apply(l, r, x);     // [l, r) 全体に魔法 x をかける
   S m = seg.prod(l, r);   // [l, r) の結果を取得

   // ▼ よく使うパターンのコピペ用 (S=要素の型, F=魔法の型)
   // 【① 区間加算・区間最大値】
   // using S = ll; using F = ll;
   // S op(S a, S b) { return max(a, b); }   S e() { return -4e18; }
   // S mapping(F f, S x) { return f + x; }
   // F composition(F f, F g) { return f + g; }
   // F id() { return 0; }

   // 【② 区間加算・区間最小値】
   // using S = ll; using F = ll;
   // S op(S a, S b) { return min(a, b); }   S e() { return 4e18; }
   // S mapping(F f, S x) { return f + x; }
   // F composition(F f, F g) { return f + g; }
   // F id() { return 0; }

   // 【③ 区間変更(置換)・区間最大値】 ※最小値の場合は op と e を変更
   // using S = ll; using F = ll; const F ID = 8e18;
   // S op(S a, S b) { return max(a, b); }   S e() { return -4e18; }
   // S mapping(F f, S x) { return (f == ID ? x : f); }
   // F composition(F f, F g) { return (f == ID ? g : f); }
   // F id() { return ID; }

5. scc_graph (強連結成分分解)
   scc_graph g(n);
   g.add_edge(u, v);       // uからvへの有向辺
   auto scc = g.scc();     //
トポロジカルソートされた二次元配列(グループごとの頂点リスト)が返る

6. mf_graph (最大流 / Dinic)
   mf_graph<ll> graph(n);
   graph.add_edge(from, to, cap);     // 容量capの辺を張る (戻り値は辺ID)
   ll f = graph.flow(start, goal);    // startからgoalへの最大流量

7. modint (自動MOD演算)
   using mint = modint1000000007; // または modint998244353
   mint a = 10;
   a += 1000000000;      // 内部で勝手に % MOD される
   cout << a.val();      // 出力時は .val() を付ける

8. LIS (最長増加部分列)
   LIS<int> lis;
   int len = lis.build(v);          // LIS の長さ (狭義増加)
   int len2 = lis.build(v, false);  // LIS の長さ (広義増加)
   auto seq = lis.restore(v);       // LIS の列を1つ復元
   // string にも対応: LIS<string> lis;

9. 座標圧縮 (compress)
   vector<ll> A = {30, 10, 20, 20};
   vector<int> B = compress(A);
   // B: {2, 0, 1, 1} となる(圧縮後の値は 0-indexed)
*/

提出情報

提出日時
問題 B - Mapping
ユーザ Rsetu45
言語 C++23 (GCC 15.2.0)
得点 200
コード長 15693 Byte
結果 AC
実行時間 1 ms
メモリ 3648 KiB

ジャッジ結果

セット名 Sample All
得点 / 配点 0 / 0 200 / 200
結果
AC × 4
AC × 19
セット名 テストケース
Sample 00_sample_00.txt, 00_sample_01.txt, 00_sample_02.txt, 00_sample_03.txt
All 00_sample_00.txt, 00_sample_01.txt, 00_sample_02.txt, 00_sample_03.txt, 01_random_1_00.txt, 01_random_1_01.txt, 01_random_1_02.txt, 02_random_2_00.txt, 02_random_2_01.txt, 02_random_2_02.txt, 03_random_3_00.txt, 03_random_3_01.txt, 03_random_3_02.txt, 04_random_4_00.txt, 04_random_4_01.txt, 04_random_4_02.txt, 04_random_4_03.txt, 04_random_4_04.txt, 04_random_4_05.txt
ケース名 結果 実行時間 メモリ
00_sample_00.txt AC 1 ms 3488 KiB
00_sample_01.txt AC 1 ms 3580 KiB
00_sample_02.txt AC 1 ms 3596 KiB
00_sample_03.txt AC 1 ms 3636 KiB
01_random_1_00.txt AC 1 ms 3472 KiB
01_random_1_01.txt AC 1 ms 3580 KiB
01_random_1_02.txt AC 1 ms 3548 KiB
02_random_2_00.txt AC 1 ms 3628 KiB
02_random_2_01.txt AC 1 ms 3452 KiB
02_random_2_02.txt AC 1 ms 3580 KiB
03_random_3_00.txt AC 1 ms 3628 KiB
03_random_3_01.txt AC 1 ms 3488 KiB
03_random_3_02.txt AC 1 ms 3648 KiB
04_random_4_00.txt AC 1 ms 3548 KiB
04_random_4_01.txt AC 1 ms 3524 KiB
04_random_4_02.txt AC 1 ms 3472 KiB
04_random_4_03.txt AC 1 ms 3472 KiB
04_random_4_04.txt AC 1 ms 3488 KiB
04_random_4_05.txt AC 1 ms 3648 KiB