ABC298 参加記録
ABC298に参加しました。現在ACできているのがA~Eなので、そのうちC,D,Eの解法を書いていきます。
C - Cards Query Problem
問題概要
までの番号のついた箱と、無数のカードがあります。以下のクエリが 1~N 個与えられるので、順に処理してください。 Q
1 i j
:新たにカード枚を取り、数 1 を書き込んでからカードを箱 i に入れる j 2 i
:箱に入っているカードを昇順で出力する(重複は、消去しない) i 3 i
:数字の書かれたカードの入っている箱の番号を昇順に出力する(重複は消去する) i
1\leq Q\leq 10^5 -
1 i j
のクエリにおいて1\leq i\leq 2\times10^5 -
3 i
のクエリにおいて1\leq i\leq 2\times10^5 - 出力すべき数字は、
個以下に収まる2\times10^5 - 入力はすべて整数
リンク:
解法
問題文がややこしい...というか、紛らわしいので、できるだけサンプルは試すことをお勧めする。
解法自体はそこまで難しくなく、いわゆるset
,multiset
を用いればよい。
実装例
#include <iostream>
#include <set>
#include <unordered_map>
#include <vector>
using namespace std;
int main() {
int n;
scanf("%d", &n);
constexpr int CARD_MAX = 2e5;
vector<multiset<int>> v1(n + 1); // v1[i]:=箱iに入っているカード
vector<set<int>> v2(CARD_MAX + 1); //v2[i]:=数字iの書かれたカードが入っている箱
int q;
scanf("%d", &q);
while (q--) {
int t;
scanf("%d", &t);
if (t == 1) {
int i,j;
scanf("%d%d", &i, &j);
v1[j].emplace(i);
v2[i].emplace(j);
} else if (t == 2) {
int i;
scanf("%d", &i);
for (const auto& card : v1[i]) {
printf("%d ", card);
}
printf("\n");
} else {
int i;
scanf("%d", &i);
for (const auto& box : v2[i]) {
printf("%d ", box);
}
printf("\n");
}
}
}
大丈夫とは思うけれど...入出力多くなりそうなので、一応scanf,printf
を使ってる。
D - Writing a Numeral
問題概要
文字列
があり、最初 S である。以下の形式のクエリが S=1 個与えられるので、順に処理せよ Q
1 x
:の末尾に数字 S を追加する。 x 2
:の先頭の文字を削除する S 3
:を S 進数表示の整数と見たときの、 10 の値を答える S \bmod998244353
1\leq Q\leq 6\times10^5 - クエリ
1
において0\leq x<10 - クエリ
2
は、 の時のみ行われる|S|>1
解法
みたいにおいてみる。文字列としてみるなら
というかんじ。
となって、これを数式で表せば
みたいになる。よってクエリ
1
はと言い換えられる。同様に考えると、クエリ
2
はであることが分かる。ということで、結局は
queue
とかでできる。
実装例
自作のmodintを使ってみる(Library)
#include <bits/stdc++.h>
#include "math/static_modint.hpp"
using namespace std;
using mint = kyopro::static_modint32<998244353>;
int main() {
mint cur = 1;
mint pw = 1;
queue<int> que;
const mint inv10 = mint(10).inv();
que.emplace(1);
int q;
scanf("%d", &q);
while (q--) {
int t;
scanf("%d", &t);
if (t == 1) {
int x;
scanf("%d", &x);
cur *= 10;
cur += x;
que.emplace(x);
pw *= 10;
} else if (t == 2) {
cur -= pw * que.front();
pw *= inv10;
que.pop();
} else {
printf("%lld\n", cur.val());
}
}
}
ローリングハッシュをみたことあると解きやすいらしい(たしかに)
E - Unfair Sugoroku
問題概要
高橋君と青木君がすごろくをします。
高橋君ははじめ地点、青木君ははじめ地点 A にいて、交互にサイコロを振ります。 B
高橋君が振るサイコロはの出目が一様ランダムに出るサイコロで、青木君が振るサイコロは 1,2,\dots,P の出目が一様ランダムに出るサイコロです。 1,2,\dots,Q
$ 地点にいるときに自分の振ったサイコロの出目が x であるとき、地点 i に進みます。 \min(x+i,N)
地点に先に着いた人をすごろくの勝者とします。 N
高橋君が先にサイコロを振るとき、高橋君が勝つ確率をで求めてください。 \bmod998244353
1\leq N\leq 100 1\leq A,B\leq N 1\leq P,Q\leq 10
解法
2人の位置を状態としてもってDPすればよい。手番が分かるように、それも持っておこう。
要は、以下のような
-
高橋君が位置dp[i][j]:= にいて青木君が位置i にいる状態で、現在の手番は高橋君。この状態から高橋君が勝てる確率j -
高橋君が位置ep[i][j]:= にいて青木君が位置i にいる状態で、現在の手番は青木君。この状態から青木君が勝てる確率j
漸化式は次のようになる。
これを実装すれば答えが得られる。計算量は
- 状態数・・・
O(N^2) - 遷移・・・
O((P+Q)\log M)(M=998244353)
なので、全体
Discussion