2022“杭电杯”中国大学生算法设计超级联赛(10)签到题5题
Posted 小哈里
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2022“杭电杯”中国大学生算法设计超级联赛(10)签到题5题相关的知识,希望对你有一定的参考价值。
Solved Problem ID Title Ratio (Accepted / Submitted)
1001 Winner Prediction 14.38% (391/2719)
1002 Photos 23.83% (107/449)
1003 Wavy Tree 37.31% (670/1796)
1004 Average Replacement 15.13% (303/2003)
1005 Apples 30.95% (26/84)
1006 Triangle Rotation 30.00% (18/60)
1007 Even Tree Split 41.73% (782/1874)
1008 Minimum Diameter 18.52% (75/405)
1009 Painting Game 26.44% (588/2224)
1010 Tree 14.78% (17/115)
1011 Maximum Triangles 14.05% (17/121)
1012 Expected Inversions 10.66% (29/272)
文章目录
7.Even Tree Split
Problem Description
You are given an undirected tree with nn nodes. It’s guaranteed that nn is even.
You are going to delete some of the edges (at least 11), and have to let each of the remaining connected components have an even number of vertices.
Calculate the number of ways to delete the edges that satisfy such constraints, modulo 998244353998244353.
Input
The first line contains an integer T(1 \\leq T \\leq 30)T(1≤T≤30) - the number of test cases.
The first line of each test case contains an integer n(1 \\leq n \\leq 10^5)n(1≤n≤10
5
) - the number of vertices on the tree.
The next n-1n−1 lines of each test case contain two integers u,v(1 \\leq u,v \\leq n)u,v(1≤u,v≤n), representing an edge between uu and vv.
It is guaranteed that the input graph is a tree with even number of vertices.
Output
For each test case, output the number of ways to delete the edges that satisfy such constraints in a single line, modulo 998244353998244353.
Sample Input
2
2
1 2
4
1 2
2 3
3 4
Sample Output
0
1
题意:
- 给出一棵n个点的树,保证n为偶数。删除树中至少一条边,让剩下的联通分量中包含的点的个数都为偶数个。求方案数%998244353。
思路:
- 对每条边,如果删去该边后两棵树点数都为偶数,则称其为好边。显见一个边集是合法的当且仅当边集内都为好边。
- 则答案为 2 c − 1 2^c-1 2c−1 ,其中 c为好边数量。时间复杂度O(n)。
- 预处理出每个点的子树大小siz[x],再dfs遍历点,对于点x,若siz[x]%2=0, 显然x的父亲边为好边,原集合可以被划分为两个合法的边集。
#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 LL maxn = 1e5+10, mod = 998244353;
vector<int>G[maxn];
LL ans = 1;
int siz[maxn];
void dfs2(int x, int f)
siz[x] = 1;
for(int y : G[x])
if(y==f)continue;
dfs2(y,x);
siz[x] += siz[y];
void dfs(int x, int f, int d)
if(siz[x]%2==0 && x!=1)
ans = (ans*2)%mod;
for(int y : G[x])
if(y==f)continue;
dfs(y,x,d+1);
int main()
IOS;
int T; cin>>T;
while(T--)
int n; cin>>n;
for(int i = 1; i <= n; i++)G[i].clear(), siz[i] = 0;
ans = 1;
for(int i = 1; i <n; i++)
int u, v; cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
dfs2(1,-1);
dfs(1,-1, 1);
cout<<ans-1<<"\\n";
return 0;
3.Wavy Tree
Wavy Tree
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 51 Accepted Submission(s): 20
Problem Description
An array a of length n is said to be wavy, if for each 1<imaxai−1,ai+1 or ai<minai−1,ai+1 holds.
You are given an array b of length n (1≤bi≤109) , consisting of integers. You want to make the array wavy. To do that you can spend some coins, with each coin you can make one element in b increase or decrease by 1. Calculate the minimum number of coins you need to spend to make the array wavy.
Input
The first line contains the number of test cases T (1≤T≤103).
The first line of each test case contains one integer n (1≤n≤106) - the length of array b .
The second line contains n integers b1,b2,⋯,bn (1≤bi≤109) - the array b .
It’s guarantee that the sum of n among all test cases is not greater than 3×106 .
Output
For each test case, output one integer, the minimum number of coins you need to spend to make the array wavy.
Sample Input
3
4
1 7 6 5
6
1 2 3 4 5 6
6
1 1 4 5 1 4
Sample Output
2
4
4
Source
2022“杭电杯”中国大学生算法设计超级联赛(10)
题意:
- 给出一个长为n的数组,你每次操作可以将其中的一个数字加一或减一,求最少操作次数让该数组成为一个波形数组。
- 波形数组的判定为,数组中除了第一个和最后一个外的元素a[i],都满足两边的元素同时大于a[i]或小于a[i]。
思路:
- 首先波形数组最多只要两种,奇数位大或者偶数位大,没有其他情况。
- 因此,分两类,先确定是奇数位为大数还是偶数位为大数。接着从左往右贪心,对每个i=2,3,4,n ,如果 ai与ai-1的大小关系不符合条件,则调整 。最后取个min即可。
- 复杂度O(n)。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e6+10;
typedef long long LL;
LL a[maxn], b[maxn];
int main()
ios::sync_with_stdio(0), cin.tie(0),cout.tie(0);
int T; cin>>T;
while(T--)
int n; cin>>n;
LL ans1 = 0, ans2 = 0;
for(int i = 1; i <= n; i++)cin>>a[i], b[i]=a[i];
//1大2小
for(int i = 2; i <= n; i++)
if(i%2==0)
if(a[i]>=a[i-1]) //波谷,不满足就调整为a[i-1]-1
ans1 += a[i]-(a[i-1]-1);
a[i] = a[i-1]-1;
else
if(a[i]<=a[i-1]) //波峰,不满足就调整为a[i-1]+1
ans1 += a[i-1]+1-a[i];
a[i] = a[i-1]+1;
//1小2大
for(int i = 2; i <= n; i++)
if(i%2==0)
if(b[i]<=b[i-1]) //波峰,不满足就调整为b[i-1]+1
ans2 += b[i-1]+1-b[i];
b[i] = b[i-1]+1;
else
if(b[i]>=b[i-1]) //波谷,不满足就调整为b[i-1]-1
ans2 += b[i]-(b[i-1]-1);
b[i] = b[i-1]-1;
cout<<min(ans1,ans2)<<"\\n";
return 0;
9.Painting Game
Painting Game
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 57 Accepted Submission(s): 23
Problem Description
There is a paper strip divided into n blank grids. For each i(1≤i<n), grid i and i+1 are considered adjacent.
Alice and Bob are going to play a game on the strip. They take turns to make move. In one move the player must paint one of the remaining blank grids black, while keeping the rule that no two black grids are adjacent.
The game ends when one of the players is unable to paint any grid, and the score of the game is defined as the total number of grids painted black. Alice wants to minimize the score, while Bob wants to maximize it.
Given n and the side starting the game, find out the final score when both players play optimally.
Input
The first line contains an integer T(1≤T≤105) - the number of test cases.
The first line of each test case contains an integer n(1≤n≤109) and a string s(s∈Alice,Bob) - the number of grids and the starting player of this game.
Output
For each test case, output the final score when both players play optimally in a single line.
Sample Input
4
3 Alice
3 Bob
19 Alice
23 Bob
Sample Output
1
2
8
10
Source
2022“杭电杯”中国大学生算法设计超级联赛(10)
题意:
- 有n个空白网格,A和B轮流操作,每次需要将一个涂为黑色,同时保持没有两个黑色网格相邻。无法涂黑时游戏结束。
- Alice 想要最小化黑格数,而Bob想要最大化它。给定n和先手是谁,求两人都最佳策略下最后的黑格子数量。
思路:
- 我们把涂黑操作想象成剪掉连续的三个格子。如果每个连续段长度都<=2 ,那么结果就确定了。
在此之前,可以发现,Alice 的一种最优策略是:选某个连续段的左数第二个格子涂黑。
Bob 的一种最优策略是:选某个连续段的左数第三个格子涂黑。 - 设f(n) , g(n) 分别为 Alice、Bob 面对长度为n的空纸带时的答案。则有f(n) = g(n-3)+1, g(n) = f(n-3)+2,注意到f(n) = f(n-7)+3, g(n) = g(n-7)+3,因此可以快速算出答案。
- 对于<=7内的边界情况可以枚举以后特判一下。
#include<bits/stdc++.h>
using namespace std;
int main()
int T; cin>>T;
while(T--)
int n; string op; cin>>n>>op;
int ans = n/7*3;
if(op[0]=='A')
if(n%7>=1) ans++;
if(n%7>=4) ans++;
if(n%7>=6) ans++;
else
if(n%7>=1) ans++;
if(n%7>=3) ans++;
if(n%7>=5) ans++;
cout<<ans<<"\\n";
return 0;
1.Winner Prediction
Winner Prediction
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 187 Accepted Submission(s): 52
Problem Description
A tournament consisting of n participants is currently taking place. The players are numbered from 1 to n. Every match is between two participants, and there are no draws. The participant who wins the most matches wins the entire tournament; if there are multiple participants tied at the first place, all of them win the tournament.
At the current state, some matches have ended, and others are yet to start. You are given the results of all ended matches. Write a program to determine whether it is possible for player 1 to win the tournament.
You are given T independent test cases. Solve each of them.
Input
The first line of input consists of a single integer T(1≤T≤100), indicating the number of test cases. Then T test cases follow.
Each of the T test cases consists of multiple lines.
The first line contains three integers n,m1,m2(1≤n≤500,1≤m1,m2≤1000), indicating the number of participants, the number of ended matches and the number of upcoming matches.
Each of the next m1 lines contains three space-separated integers x,y,z(1≤x,y≤n,x≠y,0≤z≤1), indicating an ended match between player x and player y , z=1 means player x won the match and z=0 means player y won the match.
Each of the next m2 lines contains two space-separated integers x,y(1≤x,y≤n,x≠y), indicating an upcoming match between player x and player y.
Output
For each test case, if it is possible of player 1 to win the tournament, print a line YES; otherwise print a line NO.
Sample Input
2
4 2 1
2 3 1
3 2 1
1 4
4 2 2
2 3 1
2 4 1
1 2
3 4
Sample Output
YES
NO
Source
2022“杭电杯”中国大学生算法设计超级联赛(10)
题意:
- 有n个人在进行比赛,现在有m1场已经结束的比赛,给出x和y比,z表示谁赢。还有m2场尚未进行的比赛,给出x和y将要比。 每个人获胜就可以获得1分。
- 现在可以自由安排未进行的比赛的胜负,求最优情况下1能否成为最高分(可以有其他同分)
思路:
- 注意未进行的比赛可以有1和3比试很多场,是独立的,如果算在一起可能会TLE。
- 先让 1 号选手赢下所有和他有关的比赛,设此时选手i 赢了 ai场比赛。如果存在某个 ai>a1则 1号选手不可能成为冠军。因此选手 i至多还能再赢 bi = a1-ai场比赛。
- 说实话,最大流是我未曾设想过的道路(考虑建立一张网络流图:每场未进行的比赛在图中用一个点表示,源点向它连容量为 1的边,它向它的两个参赛选手的对应点各自连容量为 1 的边,选手i 的对应点向汇点连容量为 bi的边。)计算该图最大流,若源点出发的边满流则答案为 YES ,否则为 NO 。
#include<bits/stdc++.h>
using namespace std;
//最大流模板
namespace Flow
struct Edge
int To, Val, Nxt;
Ed[10005];
int n, S, T, Head[2005], cur[2005], dis[2005], cnt;
void AddEdge(int x, int y, int val)
Ed[++cnt] = (Edge)y, val, Head[x];
Head[x] = cnt;
Ed[++cnt] = (Edge)x, 0, Head[y];
Head[y] = cnt;
bool bfs()
for (int i = 1; i <= n; i++)dis[i] = 1e9;
queue<int> Q;
Q.push(S);
dis[S] = 0;
while (!Q.empty())
int Now = Q.front();
Q.pop();
for (int i = Head[Now]; i != -1; i = Ed[i].Nxt)
if (dis[Ed[i].To] == 1e9 && Ed[i].Val)
Q.push(Ed[i].To);
dis[Ed[i].To] = dis[Now] + 1;
return dis[T] != 1e9; //汇点不可达,已求出最大流
int dfs(int x, int val)
if (x == T || val == 0)
return val;
int Out = 0;
for (int &i = cur[x]; i != -1; i = Ed[i].Nxt)
if (dis[Ed[i].To] != dis[x] + 1 || !Ed[i].Val)
continue;
int tmp = dfs(Ed[i].To, min(val, Ed[i].Val));
val -= tmp;
Out += tmp;
Ed[i].Val -= tmp;
Ed[i ^ 1].Val += tmp;
if (val == 0)
break;
return Out;
int Dinic()
int ans = 0;
while (bfs()) //bfs增广路
memcpy(cur, Head, sizeof(cur));
ans += dfs(S, 1e9);
return ans;
int n, m1, m2, s[510]; //分数
int main()
int T; scanf("%d",&T);
while(T--)
scanf("%d%d%d",&n, &m1, &m2);
for(int i = 1; i <= n; i++)s[i] = 0;
for(int i = 1; i <= m1; i++)
int x, y, z; cin>>x>>y>>z;
if(z==1)s[x]++;
else s[y]++;
Flow::n = n+m2+2; //n个选手+m2场比赛+源点汇点
Flow::S = n+m2+1; Flow::T = n+m2+2;
Flow::cnt = -1;
for(int i = 1; i <= Flow::n; i++)Flow::Head[i] = -1;
int cc = 0;
for(int i = 1; i <= m2; i++)
int x, y; cin>>x>>y;
if(x==1 || y==1) s[1]++; continue;else cc++;
Flow::AddEdge(Flow::S, n+i, 1); //源点到比赛连一条边
Flow::AddEdge(n+i, x, 1); //比赛到选手x连一条边
Flow::AddEdge(n+i, y, 1); //比赛到选手y连一条边
int ok = 1;
for(int i = 2; i <= n; i++)
if(s[i] > s[1])ok = 02022“杭电杯”中国大学生算法设计超级联赛部分题题解