题号 标题 已通过代码 通过率 团队的状态
A Everlasting Transeunt 点击查看 6/42
B Fall Guys-Perfect Match 点击查看 6/115
C Magic Ritual 点击查看 2/10
D Mi Re Do Si La? So Fa! 点击查看 21/140
E Reviewer Assignment 点击查看 217/1165
F Shannon Switching Game? 点击查看 509/1699
G Steins;Game 2 点击查看 24/59
H Wheel of Fortune 点击查看 813/2162
I Yet Another FFT Problem? 点击查看 259/3849
J Yet Another Sorting Problem! 点击查看 15/146
K You are given a tree… 点击查看 10/78

文章目录

  • H.Wheel of Fortune
  • F.Shannon Switching Game?
  • I.Yet Another FFT Problem?
  • E.Reviewer Assignment

H.Wheel of Fortune

题目描述
In the famous card-collecting game Hearthstone, there is an exciting card named Yogg Saron, Master of Fate, with a battlecry effect of “If you’ve cast 1010 spells during the game, spin the Wheel of Yogg Saron!”

Six distinct options are contained in the Wheel of Yogg Saron, with a probability of being chosen for each option. Among all options, the one with the least probability of being chosen is “Rod of Roasting.” However, this option also has the most devastating effect: Randomly cast “Pyroblast” until a player dies! Here, “Pyroblast” is a spell of mage class, with the effect of dealing 1010 damage to some unit.

Now, given the health point of you and your opponent and the health point of minions on the board, you want to know: If now a battlecry of Yogg Saron, Master of Fate is triggered and the option of “Rod of Roasting” is chosen, what is the probability of you surviving the pyroblasts and winning the game?

Formally, assume your health point is A(A>0)A(A>0), and the health point of at most77 minions on your board are a_1,a_2,\dots,a_7(a_i\geq 0,a_i=0\text{ iff this minion doesn’t exist}),a
1

,a
2

,…,a
7

(a
i

≥0,a
i

=0 iff this minion doesn’t exist), respectively. Also, your opponent’s health point is B(B>0)B(B>0) and the health point of at most 77 minions on your opponent’s board are b_1,b_2,\dots,b_7(b_i\geq 0,b_i=0\text{ iff this minion doesn’t exist})b
1

,b
2

,…,b
7

(b
i

≥0,b
i

=0 iff this minion doesn’t exist), respectively. The option of “Rod of Roasting” is equivalent to the following stochastic process:
Repeat until A\leq 0A≤0 or B\leq 0B≤0: Choose from A,B,a_1,a_2,\dots,a_7,b_1,b_2,\dots,b_7A,B,a
1

,a
2

,…,a
7

,b
1

,b
2

,…,b
7

an element xx greater than zero uniformly at random and set x\leftarrow x-10x←x−10
If B\leq 0B≤0, you win. Otherwise, your opponent wins.
输入描述:
The first line contains eight integers A,a_1,a_2,\dots,a_7(0<A\leq 10^7,0\leq a_i\leq 10^7)A,a
1

,a
2

,…,a
7

(0<A≤10
7
,0≤a
i

≤10
7
), denoting the health point of you and your minions.

The second line contains eight integers B,b_1,b_2,\dots,b_7(0<B\leq 10^7,0\leq b_i\leq 10^7)B,b
1

,b
2

,…,b
7

(0<B≤10
7
,0≤b
i

≤10
7
), denoting the health point of your opponent and your opponent’s minions.
输出描述:
Output an integer in a line, denoting the probability of you winning the game. Under the input constraints of this problem, it can be shown that the answer can be written as \frac{P}{Q}
Q
P

, where PP and QQ are coprime integers and Q\not\equiv 0\pmod {998244353}Q


≡0(mod998244353). You need to output P\cdot Q^{-1}\pmod{998244353}P⋅Q
−1
(mod998244353) as an answer, where Q^{-1}Q
−1
is the modular inverse of QQ with respect to 998244353998244353.
示例1
输入
复制
30 5 0 0 0 0 0 0
30 5 0 0 0 0 0 0
输出
复制
499122177
示例2
输入
复制
10 0 0 0 0 0 0 0
11 0 0 0 0 0 0 0
输出
复制
748683265

题意:

  • 两个人在打炉石,双方各有1个英雄和7个小怪,英雄和小怪都有自己的血量ai, bi。
  • 使用尤格萨隆命运大师技能的炎爆选项,每次随机一个人扣10点血。
  • 求A获胜的概率%998244353。

思路:

  • 可以发现答案与小怪的血量无关。
  • 对于双方英雄,排列组合有以下公式。
  • 组合数提前预处理出阶乘和逆元可以快速算出。
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0), cin.tie(0),cout.tie(0)
typedef long long LL;
const int maxn=2e6+5;
const LL mod = 998244353;

LL fac[maxn], inv[maxn];
inline LL pows(LL a, LL x) { if(x==0)return 1; LL t = pows(a, x>>1); if(x%2==0)return t*t%mod; return t*t%mod*a%mod; }
inline LL pows(LL a, LL x, LL p) { if(x==0)return 1; LL t = pows(a, x>>1, p); if(x%2==0)return t*t%p; return t*t%p*a%p; }
inline LL exgcd(LL a, LL b, LL &x, LL &y){ if(!b){ x = 1, y = 0; return a; }else{LL r = exgcd(b, a%b, x, y); LL t = x; x = y; y = t-a/b*y; return r; }}
inline void exgcd(LL a, LL b, LL &d, LL &x,  LL & y, LL MOD) { if (b==0) { d = a; x = 1; y = 0; } else { exgcd(b, a % b, d, y, x, MOD); y -= x * (a / b); } }
inline LL inv2(LL a, LL MOD) { LL d=0, x=0, y=0; exgcd(a, MOD,  d,  x, y, MOD); return d == 1 ? (x + MOD) % MOD : -1; }

LL init(){
    fac[0]=inv[0]=1;
    for(int i = 1; i < maxn; i++){
        fac[i]=fac[i-1]*i%mod; inv[i]=inv2(fac[i],mod);
    }return 0;
}
LL C(int x, int y) {
    if(y<0 || y>x)return 0;
    return fac[x]*inv[y]%mod*inv[x-y]%mod;
}

LL a,b,c;
LL ans=0;
int main(){
    IOS;
    init();
    cin>>a;
    for(int i=1;i<=7;i++) cin>>c;
    cin>>b;
    for(int i=1;i<=7;i++) cin>>c;
    if(a%10==0) a=a/10;else a=a/10+1;
    if(b%10==0) b=b/10;else b=b/10+1;
    LL kk=pows(2,b,mod);
    for(int i=0;i<a;i++){
        ans=(ans+inv2(kk,mod)*C(i+b-1,b-1)%mod)%mod;
        kk=kk*2%mod;
    }
    cout<<(ans+mod)%mod;
    return 0;
}

F.Shannon Switching Game?


题目描述
The Shannon switching game is a two-player game invented by Claude Shannon, the ``father of information theory’’ sometime before 1951. In the game, two players take turns choosing and removing the edges of an arbitrary graph. One player aims to connect two distinguished vertices by a path of edges chosen by him/her. The other player aims to prevent this. The formal definition is as follows:
Given an undirected graph G=(V, E)G=(V,E) possibly with multiple edges and two vertices s, t\in Vs,t∈V. Two players Join Player and Cut Player take turns doing the following operation, starting from Cut Player:
Choose an edge (u,v)\in E(u,v)∈E, and remove the edge (u,v)(u,v) from GG.
The game ends when either player cannot make a valid move, and the winner of the game is determined as follows:
If the set of edges chosen by Join Player connects ss and tt, then Join Player wins.
Otherwise, Cut Player wins.
Alfred Lehman solved this problem in 1964 in a paper named A Solution of the Shannon Switching Game. Lehman observed that the structure of this game is intimately related to a combinatorial structure named matroid and presented a solution based on the property of matroids.

Recently, when gispzjz came across this problem, he understood the original problem and the solution immediately and invented the following variant of the game:
Given an undirected graph G=(V,E)G=(V,E) possibly with multiple edges and two vertices s, t\in Vs,t∈V. There is a token initially placed at ss. Two players Join Player and Cut Player take turns doing the following operation, starting from Cut Player:
If it is Join Player’s turn, assuming the token is currently at vertex uu, Join Player can choose an incident edge (u,v)\in E(u,v)∈E, remove the edge (u,v)(u,v) from GG and move the token to vertex vv;
If it is Cut Player’s turn, assuming the token is currently at vertex uu, Cut Player can choose an incident edge (u,v)\in E(u,v)∈E and remove the edge (u,v)(u,v) from GG.
The game ends when either player cannot make a valid move, and the winner of the game is determined as follows:
If the token ever reaches tt during the game, then Join Player wins.
Otherwise, Cut Player wins.
gispzjz quickly came up with a solution for determining the winner of the game under the optimal strategy of both players, but the solution can’t fit on the rest of the page. Can you help him write the solution down?
输入描述:
The first line of input contains an integer T (1\leq T\leq 20)T(1≤T≤20), denoting the number of test cases.

For each test case, the first line of the input contains four integers n,m,s,t(1\leq n\leq 100,1\leq m\leq 10000, 1\leq s,t\leq n,s\neq t)n,m,s,t(1≤n≤100,1≤m≤10000,1≤s,t≤n,s


=t), denoting the number of vertices and edges in the graph, the given starting vertex and ending vertex, respectively.

Then mm lines follow, with each line containing two integers u,v(1\leq u,v\leq n,u\neq v)u,v(1≤u,v≤n,u


=v), denoting an edge (u,v)\in E(u,v)∈E in the graph. Note that there may be multiple edges in the graph but not self loops.
输出描述:
For each test case, if Join Player wins under optimal strategy of both players, output “Join Player”(without quotes) in a line, otherwise output “Cut Player”(without quotes) in a line .
示例1
输入
复制
3
2 1 1 2
1 2
2 2 1 2
1 2
1 2
3 3 1 2
1 2
2 3
1 3
输出
复制
Cut Player
Join Player
Cut Player
备注:
In the first test case of the sample test, Cut Player can remove the only edge and win the game.

In the second test case, no matter which edge Cut Player picks, Join Player can choose the remaining edge and move the token to vertex 22, thus winning the game.

In the third test case, Cut Player can remove the edge (1,2)(1,2), then Join Player is only allowed to choose edge (1,3)(1,3) and move the token to vertex 33, then Cut Player can remove the edge (2,3)(2,3) and win the game.

题意:

  • n个点m条边的图,图有重边,没自环。初始时有一个token在s点,两个玩家Join和Cut轮流操作,Cut先手。
  • Cut每次移除一条和token所在位置相邻的边, Join 每次可以将token沿着一条未删除边移动。如果token最后能移到t点则Join获胜,否则Cut获胜。
  • 求双方最优策略下的胜者。

思路:

  • 可以发现,且因为最后要走到t,但是cut一定可以在join之前拦截那条路,所以说连终点的那个点走到终点一定有两条路,比如说有重边。
  • 那么我们终点就可以转移到这个点(和终点相连的,有重边的点),记这个点为可行点。那么后面就是能到两个可行点的都是可行点(有两条路)。最后如果起点能够拓展到可行点集合中,那么Join就能获胜,否则Cut获胜。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 510;
int e[maxn][maxn], ok[maxn];

int main(){
    int T;  cin>>T;
    while(T--){
        int n, m, s, t;  cin>>n>>m>>s>>t;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= n; j++)e[i][j] = 0;
            ok[i] = 0;
        }
        for(int i = 1; i <= m; i++){
            int u, v;  cin>>u>>v;
            e[u][v]++;  e[v][u]++;
        }
        ok[t] = 1;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= n; j++){
                int tmp = 0;
                for(int k = 1; k <= n; k++){
                    if(ok[k]){
                        tmp += e[j][k]*ok[k];
                    }
                }
                //j相连的可行点>2或者j与可行点有重边, j也是可行点
                if(tmp>=2)ok[j] = 1;
            }
        }
        if(ok[s]){
            cout<<"Join Player\n";
        }else{
            cout<<"Cut Player\n";
        }
    }
    return 0;
}

/*
1
4 5 1 4 
1 2
1 2
2 3
3 4
3 4
Cut

1
5 8 1 4 
1 2
1 2
2 3
3 4
3 4
5 2
5 3
5 4
Join
*/

I.Yet Another FFT Problem?

题目描述
triplea and tripleb have two integer arrays A=[a_1,a_2,\dots,a_n]A=[a
1

,a
2

,…,a
n

] and B=[b_1,b_2,\dots,b_m]B=[b
1

,b
2

,…,b
m

], respectively. One day they came up with the following problem:
Does there exists a pair of numbers in arrays AA and BB, such that their absolute difference is the same?

However, triplea and tripleb care about their data privacy, so they don’t want to expose their array directly to each other. That’s why they turn to you------triplec. Can you help them solve this problem?

Formally, you need to determine: do there exist four indices 1\leq i,j\leq n,1\leq k,l\leq m1≤i,j≤n,1≤k,l≤m, such that i\neq ji


=j, k \neq lk


=l and |a_i-a_j|=|b_k-b_l|∣a
i

−a
j

∣=∣b
k

−b
l

∣.
输入描述:
The first line contains two integers n,m(2\leq n,m\leq 10^6)n,m(2≤n,m≤10
6
), denoting the sizes of array AA and BB, respectively.

The next line contains nn integers a_1,a_2,\dots,a_n(0\leq a_i\leq 10^7)a
1

,a
2

,…,a
n

(0≤a
i

≤10
7
), denoting the elements of array AA.

The next line contains mm integers b_1,b_2,\dots,b_m(0\leq b_i\leq 10^7)b
1

,b
2

,…,b
m

(0≤b
i

≤10
7
), denoting the elements of array BB.
输出描述:
If there exist four indices 1\leq i,j\leq n,1\leq k,l\leq m1≤i,j≤n,1≤k,l≤m, such that i\neq ji


=j, k\neq lk


=l and |a_i-a_j|=|b_k-b_l|∣a
i

−a
j

∣=∣b
k

−b
l

∣, output i,j,k,li,j,k,l in a line, otherwise output -1−1 in a line.
示例1
输入
复制
4 4
2 4 8 16
3 9 27 81
输出
复制
1 3 1 2

题意:

  • 给定一个长为n的A数组和长为m的B数组,求是否存在一组(i,j)(k,l)满足|ai-aj|=|bk-bl|。
  • 若存在输出任意一组,不存在输出-1。
  • n, m < 1e6, ai, bi < 1e7.

思路:

  • 首先考虑特殊情况,若a中有重复元素,b中也有,那么直接两两配对输出即可。
  • 然后,我们将原式拆开,题目等价于求一组满足ai+bl = aj+bk。即两组位置不同的ai+bj值相等。
  • 我们将原数组去重后,暴力遍历数组a与b,vis记录每次出现的ai+bj,如果有相等,那就输出即可。
  • 因为ai+bj<2e7,由抽屉原理可以得到2e7次内必定出现正解(ai+bj会第二次出现),因此双重循环暴力不会超时。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e7+10;

int main(){
    ios::sync_with_stdio(0), cin.tie(0),cout.tie(0);
    //输入并去重存入pa,fa标记首次出现位置
    int n, m;  cin>>n>>m;
    vector<int>a(n), b(m);
    vector<int>fa(maxn, -1), fb(maxn, -1);
    vector<int>pa, pb;
    array ans{-1,-1,-1,-1};
    for(int i = 0; i < n; i++){
        cin>>a[i];
        if(fa[a[i]] == -1){
            fa[a[i]] = i;
            pa.push_back(i);
        }else{
            ans[0] = fa[a[i]];
            ans[1] = i;
        }
    }
    for(int i = 0; i < m; i++){
        cin>>b[i];
        if(fb[b[i]] == -1){
            fb[b[i]] = i;
            pb.push_back(i);
        }else{
            ans[2] = fb[b[i]];
            ans[3] = i;
        }
    }

    //统计答案
    if(ans[0] != -1 && ans[2]!=-1){         //ab数组均有重复元素, 直接输出
        for(int i = 0; i < 4; i++)
            cout<<ans[i]+1<<' ';
        return 0;
    }
    vector<array<int,2>>f(2*maxn, {-1,-1});
    for(int i : pa){                        //找到两组相等的ai+bj,因为无重复,直接输出即可
        for(int j : pb){
            if(f[a[i]+b[j]][0] == -1){
                f[a[i]+b[j]] = {i,j};
            }else{
                cout<<f[a[i]+b[j]][0]+1<<' '<<i+1<<" "<<j+1<<" "<<f[a[i]+b[j]][1]+1<<"\n";
                return 0;
            }
        }
    }
    cout<<"-1\n";
    return 0;
}

E.Reviewer Assignment

题目描述
gispzjz likes playing DotA2 and has recently become the chair of the celebrated conference SODA (Symposium on DotA2) in the community of DotA2, which focuses on research topics related to the design and analysis of strategies in DotA2 gaming.

Now the deadline for the Call For Papers of the 2023 Symposium on DotA2 has passed, and gispzjz has received a huge amount of papers! Fortunately, there are also many reviewers for the SODA conference, and gispzjz’s job is to assign the papers to the reviewers for review. However, as there may be conflicts between paper writers and reviewers, each reviewer is only allowed to review a certain subset of the papers. Also, to avoid putting too much work on each reviewer, gispzjz should assign exactly one paper to each reviewer, while each paper is allowed to be reviewed by multiple or even no reviewers.

As the conference chair, gispzjz wants each paper to be fairly reviewed, so he wants to assign papers to reviewers such that the number of papers reviewed at least once is maximized, and under that constraint, the number of papers reviewed at least twice is maximized, then under both previous constraints, the number of papers reviewed at least three times is maximized, et cetera. Surely gispzjz would easily come up with the optimal assignment, but he just went to play DotA2 and left the problem for you.
输入描述:
The first line of input contains two integers n, m(1\leq n,m\leq 400)n,m(1≤n,m≤400), denoting the number of reviewers and papers, respectively.

Then nn lines follow, each line containing a string of length mm consisting of 00s and 11s, where the j(1\leq j\leq m)j(1≤j≤m)-th character of the i(1\leq i\leq n)i(1≤i≤n)-th string is 11 if the ii-th reviewer is allowed to review the jj-th paper, and isn’t otherwise.
输出描述:
If there is no way to assign the papers to the reviewers such that each reviewer receives exactly one paper, output -1−1 in a line. Otherwise, output a line with nn integers a_1,a_2,\dots,a_n(1\leq a_i\leq m)a
1

,a
2

,…,a
n

(1≤a
i

≤m), denoting the a_ia
i

-th paper is assigned to the ii-th reviewer in the optimal assignment. If there are more than one optimal assignment, outputting any of them is considered as correct.
示例1
输入
复制
3 3
111
110
100
输出
复制
3 2 1
示例2
输入
复制
3 3
111
111
000
输出
复制
-1
示例3
输入
复制
5 3
010
010
101
011
100
输出
复制
2 2 1 3 1
备注:
For the third sample test, 2 2 3 3 1 is also a valid output.

题意:

  • 有m篇论文和n个审稿人(<400),给出每个审稿人能审论文的集合,要求给每个审稿人安排一篇论文。
  • 令f(i)表示被至少i个审稿人审过的论文数量,要求求出一种分配方案,使得(f(1),f(2),…,f(n))字典序最大。
  • 输出第i篇论文由哪个审稿人审理。

思路:

  • 注意到要求f(1)最大就是求二分图最大匹配,可以用最大流解决。原问题可以对于i=1-n在不改变f(1),f(2),…f(i-1)的情况下最大化f(i),可以通过做n次最大流得到,每次在上一次最大流结果的基础上建图。
  • 也可直接建如下最小费用流图: 源点向每个审稿人连接容量为1,花费为0的边, 每个审稿人向能审的论文连接容量为1,花费为0的边,每篇论文向汇点连接n条容量为1,花费为1,2,…,n的边,这里花费的选择也不唯一,只要使得每篇论文被审1,2,3…,n次的花费是递增严格凸函数即可。
#include<bits/stdc++.h>
using namespace std;

int main(){
    ios::sync_with_stdio(0), cin.tie(0),cout.tie(0);
    int n, m;  cin>>n>>m;  //n篇论文, m个审稿人
    vector<string>s(n);
    for(int i = 0; i < n; i++){
        cin>>s[i];
        if(s[i] == string(m,'0')){
            cout<<"-1\n";  return 0;
        }
    }
    
    vector<int>xy(n, -1), cnt(m);  //xy:论文v最终由谁审理
    for(int i = 0; i < n; i++){    //最大化被至少i个审稿人审过的论文数量

        //二分图最大匹配, KM
        vector<int>vis(n+m);       //n篇论文和m个审稿人最大匹配
        vector<int>prev(n+m, -1);  //prev:论文v当前由谁审理, 审稿人审哪篇论文
        function<void(int)>dfs = [&](int x){
            vis[x] = 1;
            if(x<n){ //x是论文
                for(int y = 0; y < m; y++){
                    //如果审稿人y未匹配且论文x能被y审理,就匹配
                    if(!vis[y+n] && s[x][y]=='1'){
                        prev[y+n] = x;
                        dfs(y+n); //找增广路,这个审稿人能否替换为审其他的论文
                    }
                }
            }else{  //x是审稿人
                int y = x-n;
                for(int x = 0; x < n; x++){
                    //如果当前这篇论文没人审核, 且之前是审稿人y审的,那就继续由y审
                    if(!vis[x] && xy[x]==y){
                        prev[x] = y+n;
                        dfs(x);
                    }
                }
            }
        };
        dfs(i);

        //交替路是增广路, y为匹配点
        int y = -1;
        for(int i = 0; i < m; i++){
            if(vis[i+n] && (y==-1 || cnt[i]<cnt[y])){
                y = i;
            }
        }
        cnt[y]++;
        for(int j = y+n; j!=-1; j = prev[prev[j]]){
            xy[prev[j]] = j-n;
        }
    }
    for(int i = 0; i < n; i++){
        cout<<xy[i]+1<<" \n"[i==n-1];
    }
    return 0;
}