うーん
— ボンド@競プロ (@bond_cmprog) June 27, 2020
Bondo416さんのAtCoder Beginner Contest 172での成績:1173位
パフォーマンス:1450相当
レーティング:1268→1287 (+19) :)#AtCoder #ABC172 https://t.co/ELyawAHPO9
A - Calc
問題文の通りを出力
提出コード
void solve(){ int a; cin >> a; cout << a + a*a + a*a*a << endl; }
B - Minor Change
の個数を数える
提出コード
void solve(){ string S, T; cin >> S >> T; int cnt = 0; REP(i,S.size()) if(S[i] != T[i]) cnt++; cout << cnt << endl; }
C - Tsundoku
いつもより難しめ?
取り敢えず貪欲で考えてみるけど後々得になるパターンがあって駄目そう
片方を幾つ取るかを固定してみると、もう片方は累積和と二分探索を使うことでで求めることが出来る
実装はC++だとupper_boundを使うのが一番楽そう
提出コード
void solve(){ int N, M, K; cin >> N >> M >> K; vector<int> A(N), B(M); vector<ll> cum(N+1); REP(i,N) cin >> A[i]; REP(i,M) cin >> B[i]; for(int i=0;i<N;i++) cum[i+1] = cum[i] + A[i]; cum.push_back(LINF); int ans = 0; ll sum = 0; REP(i,M+1){ if(i > 0) sum += B[i-1]; if(sum > K) break; int num = upper_bound(cum.begin(), cum.end(), K - sum) - cum.begin() - 1; chmax(ans, num + i); } cout << ans << endl; }
D - Sum of Divisors
想定解が綺麗
本番はosa_k法を使ってに対して素因数分解を行い約数の組み合わせの個数を求めた
これはちょっと無駄があって、素因数分解をしなくてもごとにその倍数を加算していく方針でも調和級数となって求めることが出来る
さらにこの調和級数部分は等差数列の和として求めることが出来る
これが想定解でで解くことが出来る
でも解けるらしい?
提出コード(osa_k法)
template<typename T> vector<T> smartPrimeFactors(T n) { vector<T> spf(n + 1); for (int i = 0; i <= n; i++) spf[i] = i; for (T i = 2; i * i <= n; i++) { // 素数だったら if (spf[i] == i) { for (T j = i * i; j <= n; j += i) { // iを持つ整数かつまだ素数が決まっていないなら if (spf[j] == j) spf[j] = i; } } } return spf; } template<typename T> map<T, T> factorize(T x, vector<T> &spf) { map<T, T> ret; while (x > 1) { ret[spf[x]]++; x /= spf[x]; } //sort(ret.begin(), ret.end()); return ret; } void solve(){ int N; cin >> N; auto spf = smartPrimeFactors(N); ll ans = 0; for(int i=1;i<=N;i++){ auto res = factorize(i, spf); ll tmp = 1; for(auto [a, b] : res) tmp *= (b + 1); ans += (ll)i * tmp; } cout << ans << endl; }
void solve(){ int N; cin >> N; ll ans = 0; for(int i=1;i<=N;i++){ for(int j=i;j<=N;j+=i) ans += j; } cout << ans << endl; }
void solve(){ int N; cin >> N; ll ans = 0; for(int i=1;i<=N;i++){ ll n = N / i; ans += n * (n + 1) / 2 * (ll)i; } cout << ans << endl; }
E - NEQ
まず、となるような個数を固定して考えてみる
この時、その選び方はM個の中からになるものをk個順番に並べるのに通り
それ以外の部分をAとBそれぞれM-k個の中からN-k個を順番に並べるのに通りとなる
また、N個のうちどのk個を選ぶかで通り出来る
よってkを固定したときの場合の数はとなる
問題は、任意のについてを満たすものを数える必要があるが、これは包除原理によって求めることが出来る
各について、を求めてその総和が答えとなる
提出コード
void solve(){ int N, M; cin >> N >> M; mint ans = 0; for(int k=0;k<=N;k++){ mint val = bc.com(N, k) * bc.perm(M, k) * bc.perm(M-k, N-k) * bc.perm(M-k, N-k); if(k & 1) ans -= val; else ans += val; } cout << ans << endl; }
F - Unfair Nim
操作後のの数をと置くとNimの必勝法から
となれば良いことがわかる
上記のをとすると
, を満たせば良い
また移動の条件としてを満たす必要がある
xorの性質を考えるとの時は不可能なのでとなる
ここで 2 (x & y) が成り立つことを考えると
x & y となる
この時、x & yが非負整数にならないと不可能
また、x & y とで共通しているbitがあればその場合も不可能
それ以外の場合、条件を満たす範囲で上位bitから貪欲にx & yにbitを割り振っていけばいい
提出コード
void solve(){ int n; cin >> n; vector<ll> a(n); REP(i,n) cin >> a[i]; ll z = 0; for(int i=2;i<n;i++) z ^= a[i]; if(a[0] + a[1] < z){ cout << -1 << endl; return; } ll xy = a[0] + a[1] - z; if(xy & 1){ cout << -1 << endl; return; } xy >>= 1; if(xy & z){ cout << -1 << endl; return; } ll ans = xy; for(int i=40;i>=0;i--){ if((z >> i & 1) && ans + (1LL << i) <= a[0]) ans += (1LL << i); } if(ans == 0 || ans > a[0]) cout << -1 << endl; else cout << a[0] - ans << endl; }