---
# System prepended metadata

title: TTPC2022

---

# TTPC2022

例：

Python
```python=
import sys
N = int(sys.stdin.readline())
print("N =", N)
S = sys.stdin.readline().rstrip()
print("S =", S)
```

C++
```cpp=
#include<iostream>
#include<string>
using namespace std;

int main(){
    int N;
    string S;
    cin >> N >> S;
    cout << "N = " << N << "\nS = " << S << '\n';
}
```

## A
担当：nickname
```Python=
from math import gcd
x, y = map(int, input().split())
d = gcd(x-2015, y-x)
ans = set()
for i in range(1, d+1):
    if i*i > d: break
    if d%i == 0: ans.add(i); ans.add(d//i)
print(*sorted(ans), sep="\n")
```

## B
担当：ぽんた
```cpp=
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
#define rep(i, n) for (int i = 0; i < (int)(n); ++i)
#define rrep(i, n) for (int i = (int)(n)-1; i >= 0; --i)
#define rep2(i, a, b) for (int i = (int)a; i < (int)(b); ++i)
#define rrep2(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); --i)
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
constexpr int MAX_N = 10000;

int main(){
    int N, X;
    scanf("%d %d", &N, &X);
    int dp[2][MAX_N];
    memset(dp,-1,sizeof dp);
    string now = to_string(X);
    sort(now.begin(), now.end());
    do{
        dp[0][stoi(now)] = 0;
    }while(next_permutation(now.begin(), now.end()));
    rep(i, N){
        int A;
        scanf("%d", &A);
        rep(j, MAX_N) dp[(i^1)&1][j] = dp[i&1][j];
        rep2(j, A, MAX_N) if(dp[i&1][j] >= 0){
            int left = j - A;
            string now = to_string(left);
            sort(now.begin(), now.end());
            do{
                chmax(dp[(i^1)&1][stoi(now)], dp[i&1][j]+1);
            }while(next_permutation(now.begin(), now.end()));
        }
    }
    printf("%d\n", *max_element(dp[N&1],dp[N&1] + MAX_N));
    return 0;
}
```

## C
担当：Shiro
```python=
import random
import sys
input = lambda: sys.stdin.readline().rstrip()
ii = lambda: int(input())
mi = lambda: map(int, input().split())
li = lambda: list(mi())
inf = 2 ** 63 - 1
mod = 998244353
from bisect import bisect_left, bisect_right
import itertools

n = 100000

a = [[random.randint(0, 998244353) for _ in range(n)] for _ in range(5)]

for i in range(5):
    a[i].sort()


ans = 0
for x in range(5):
    c = a[x]
    s = [0, 1, 2, 3, 4]
    s.remove(x)
    for i in range(n):
        le = [0] * 5
        lt = [0] * 5
        ge = [0] * 5
        gt = [0] * 5
        for now in range(5):
            le[now] = bisect_right(a[now], c[i])
            lt[now] = bisect_left(a[now], c[i])
            ge[now] = n - le[now]
            gt[now] = n - lt[now]
        cnt = 1
        for v in itertools.combinations(s, 2):
            for now in range(5):
                if now in v:
                    if x < now:
                        cnt *= le[now]
                    else:
                        cnt *= lt[now]
                elif now != x:
                    if x < now:
                        cnt *= ge[now]
                    else:
                        cnt *= gt[now]
                cnt %= mod
            ans += c[i] * cnt
        ans %= mod
print(ans)
```

## D
担当：nick、ぽんた
木DPでいけそう。持つ情報は[頂点が反転されているか][部分木で黒で塗られている頂点数]
```cpp=
#include<cstdio>
#include<vector>
#include<stack>
#include<cstring>
using namespace std;

int main(){
    int N;
    scanf("%d", &N);
    int A[N];
    for(int i = 0; i < N; ++i) scanf("%d", A + i);
    vector<int> adj[N];
    for(int i = 1; i < N; ++i){
        int tmp1, tmp2;
        scanf("%d %d", &tmp1, &tmp2);
        --tmp1;--tmp2;
        adj[tmp1].push_back(tmp2);
        adj[tmp2].push_back(tmp1);
    }
    int dp[N][2];
    memset(dp,0,sizeof dp);
    bool has_been_discovered[N], has_been_exited[N], has_child[N];
    memset(has_been_discovered, 0, sizeof has_been_discovered);
    memset(has_been_exited, 0, sizeof has_been_exited);
    memset(has_child, 0, sizeof has_child);
    stack<int> stk;
    stk.push(0);
    while(!stk.empty()){
        int u = stk.top(); stk.pop();
        if(has_been_discovered[u]){
            if(has_child[u]) dp[u][1] = -500;
            for(auto i : adj[u]){
                if(has_been_exited[i]){
                    //現在注目している頂点の親はdpの更新式に入れない
                    //dpの更新式
                    int tmp[2];
                    tmp[0] = max(dp[i][0] + dp[u][0], dp[i][1] + dp[u][1]);
                    tmp[1] = max(dp[i][1] + dp[u][0], dp[i][0] + dp[u][1]);
                    dp[u][0] = tmp[0];
                    dp[u][1] = tmp[1];
                }
            }
            ++dp[u][A[u]^1];
            has_been_exited[u] = true;
        }else{
            has_been_discovered[u] = true;
            stk.push(u);
            for (auto i : adj[u]){
                if(!has_been_discovered[i]){
                    has_child[u] = true;
                    stk.push(i);
                }
            }
        }
    }
    printf("%d\n", max(dp[0][0], dp[0][1]));
    return 0;
}
```

## E
担当：shiro
部分点解法を書きます
文字列A+Bを考えて、前後から交互に貪欲に取っていく
部分点もらえました
```cpp=
#include<iostream>
#include<string>
using namespace std;
#define rep(i, n) for (int i = 0; i < (int)(n); ++i)
#define rrep(i, n) for (int i = (int)(n)-1; i >= 0; --i)
#define rep2(i, a, b) for (int i = (int)a; i < (int)(b); ++i)
#define rrep2(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); --i)
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
int main(){
    cin.tie(nullptr);
    std::ios_base::sync_with_stdio(false);
    string A, B;
    getline(cin, A);
    getline(cin, B);
    int len_A = A.length(), len_B = B.length();
    int next_A[len_A][53], next_B[len_B][53];
    auto char_to_idx = [](char x){
        if(x < 'A') return 52;
        else return x <= 'Z' ? x - 'A' : 26 + (x - 'a');
    };
    fill(next_A[len_A-1], next_A[len_A-1]+53, -1);
    next_A[len_A-1][char_to_idx(A[len_A-1])] = len_A-1;
    rrep(i, len_A-1){
        copy(next_A[i+1], next_A[i+1]+53, next_A[i]);
        next_A[i][char_to_idx(A[i])] = i;
    }
    fill(next_B[0], next_B[0]+53, -1);
    next_B[0][char_to_idx(B[0])] = 0;
    rep(i, len_B-1){
        copy(next_B[i], next_B[i]+53, next_B[i+1]);
        next_B[i+1][char_to_idx(B[i+1])] = i+1;
    }
    int Q;
    cin >> Q;
    cin.ignore();
    rep(_,Q){
        string S;
        getline(cin, S);
        int ok_A = 0;
        int now = 0;
        int len_S = S.length();
        while(ok_A < len_S){
            now = next_A[now][char_to_idx(S[ok_A])]+1;
            if(!now) break;
            ++ok_A;
            if(now == len_A || ok_A == len_S-1) break;
        }
        int ok_B = len_S-1;
        now = len_B-1;
        while(ok_B >= 0){
            now = next_B[now][char_to_idx(S[ok_B])]-1;
            if(now < -1) break;
            --ok_B;
            if(now == -1 || ok_B == 0) break;
        }
        if(ok_A <= ok_B) cout << "-1\n";
        else{
            int answer = len_S;
            rep2(i, ok_B+1, ok_A+1) chmin(answer, abs((i<<1) - len_S));
            cout << answer << '\n';
        }
    }
    return 0;
}
```
```console=
ok_A = 2, ok_B = 1, len_S = 14
10

ok_A = 6, ok_B = 0, len_S = 16
4

ok_A = 6, ok_B = 3, len_S = 16
4

ok_A = 9, ok_B = 9, len_S = 10
-1

ok_A = 1, ok_B = 0, len_S = 4
2

ok_A = 0, ok_B = 3, len_S = 16
-1

ok_A = 2, ok_B = 17, len_S = 23
-1

ok_A = 16, ok_B = 19, len_S = 50
-1

ok_A = 9, ok_B = 8, len_S = 15
3

ok_A = 4, ok_B = 0, len_S = 5
1
```


## F
担当：nick
最初に全てを2倍すると整数のみで考えられる←下の方針だとこれの意味がなくなっている……
https://atcoder.jp/contests/agc049/tasks/agc049_d
↑元ネタ？
↓WA
i番目の有効範囲
i番目とi+1番目は独立して動けると考えてよいのか？
問題の条件はこれと一緒？
A[i - 1] - A[i] >= A[i] - A[i + 1]
1のとき X = -inf
＊R1 - A[1] >= Xを満たして、L2 <= A[1] <= R2 であるような最大のA[1]を取る
1 3 1 
5 6 5
```python=
n = int(input())
l = [2*v for v in map(int, input().split())]
r = [2*v for v in map(int, input().split())]
xmin = l[0]; xmax = r[0]
for i in range(1, n-1):
    if xmax+r[i+1] < 2*l[i] or 2*r[i] < xmin+l[i+1]: print("No"); break
    xmin = max((xmin+l[i+1])//2, l[i])
    xmax = min((xmax+r[i+1])//2, r[i])
else: print("Yes")
```
```python=
n = int(input())
l = [2*v for v in map(int, input().split())]
r = [2*v for v in map(int, input().split())]
xmin = [l[0], l[1]]
xmax = [r[0], r[1]]
for i in range(2, n):
    if 2*xmax[i-1]-xmin[i-2] < l[i] or r[i] < 2*xmin[i-1]-xmax[i-2]: print("No"); break
    xmin.append(max(2*xmin[i-1]-xmax[i-2], l[i]))
    xmax.append(r[i])
    xmax[i-1] = min(xmax[i-1], (xmax[i-2]+xmax[i])//2)
else: print("Yes")
```
## G
担当：
```python=
n = int(input())
l = list(map(int, input().split()))
r = list(map(int, input().split()))
ans = 0
for d in range(-10**5+1, 10**5):
    if abs(d)*(n-1) >= 10**5: continue
    mi = 1
    ma = 10**5
    for i, (li, ri) in enumerate(zip(l, r)):
        mi = max(mi, li-d*i)
        ma = min(ma, ri-d*i)
    ans += max(ma-mi+1, 0)
print(ans)
```

## H
担当：shiro

メモリ制限小さすぎ、隣接行列持っただけで終わる
SCC+トポロジカルソートでDAGにできる。DAGとしてよい（強連結は1つの色で塗るのが最適）
以下のようなアルゴリズムで解ける？

1.色のついてないうち、番号が最小の頂点を選ぶ
2.それと、そこから到達できる頂点を全て同じ色で塗る
3.色++
↑嘘

DAGで2つのパスがあるとき、枝分かれした2つで同じ色を塗ることはできない
1つのパスは同じ色で塗ることができる
・DAGを最小本数のパスに分解せよという問題になる
https://kyopro.hateblo.jp/entry/2018/06/04/000659
↑これっぽい　フローでできる

```python=
n, m = map(int,input().split())

edges = [[i - 1 for i in li()] for _ in range(m)]

S = scc(n, edges)

leader = [-1] * n
for x, v in enumerate(S):
    for i in v:
        leader[i] = x

edge2 = []
for u, v in edges:
    if leader[u] != leader[v]:
        edge2.append((leader[u], leader[v]))
N = len(S)
G = mf_graph(2 * N + 2)
sink = 2 * N
tar = 2 * N + 1
for i in range(N):
    G.add_edge(sink, i, 1)
    G.add_edge(N + i, tar, 1)
e = {}

for u, v in edge2:
    if u != v:
        G.add_edge(u, N + v, 1)

f = G.flow(sink, tar)

print(G.edges())
U = dsu(N)
ed = []
for v in G.edges():
    if v['flow'] == 1 and 0 <= v['from'] < N and N <= v['to'] < 2 * N:
        ed.append((v['from'], v['to']))

assert N - f == max(ans)
print(*ans)
```
## K
担当：

## L
担当：

0 1 | 2 3 みたいなグループに分けたとき、全部の数が、元いるグループと別のところにいる必要がある
少なくともi個の数が同じグループにとどまっている場合の数→包除原理？
違反がiグループであるような入れ方の数

0 1 | 2 3のとき、
それぞれのグループのmin 0 2 を取る。
これは元と違うグループにいないといけないので、かく乱順列で1通り。

1グループ違反: グループを1つ選んで、その中からそのグループにとどめるやつを選んで、残りは好きに並べる Choose(n, 1) * m * (MN - 1)!
2グループ違反: グループを2つ選んで ~~ Choose(M, 2) * N^2 * (MN - 2)!
0 1 2 3 4 5
3 2 のとき、同じグループの順序を考慮しないと10通りになる
0 2 4
(2, 4, 1, 5, 0, 3)
(2, 3, 4, 5, 0, 1), (2, 4, 0, 5, 1, 3), (3, 5, 1, 4, 0, 2), (3, 5, 0, 4, 1, 2), (3, 4, 0, 5, 1, 2), (3, 4, 1, 5, 0, 2), (2, 5, 1, 4, 0, 3), (4, 5, 0, 1, 2, 3), (2, 5, 0, 4, 1, 3)


N個のグループそれぞれがN-1個のグループに自分たちの持つM個を配布する
配布されたあと各グループがM個もっていればよい
0 1 2
3 0 5
6 7 0

2 2
0 2
2 0

i番目のグループからj番目のグループに配布する数をa[i][j]とするとsum(a[i][\*])=sum(a[\*][j])=M
a[i][i]=0

## M
担当：
## N
担当：

## O
担当：
