目录
L1-1 今天我要赢 (5 分)
L1-2 种钻石 (5 分)
L1-3 谁能进图书馆 (10 分)
L1-4 拯救外星人 (10 分)
L1-5 试试手气 (15 分)
L1-6 斯德哥尔摩火车上的题 (15 分)
L1-7 机工士姆斯塔迪奥 (20 分)
L1-8 静静的推荐 (20 分)
L2-1 插松枝 (25 分)
L2-2 老板的作息表 (25 分)
L2-3 龙龙送外卖 (25 分)
L2-4 大众情人 (25 分)
L3-1 千手观音 (30 分)
L3-2 关于深度优先搜索和逆序对的题应该不会很难吧这件事 (30 分)
L3-3 教科书般的亵渎 (30 分)
说明:这次比赛中写了前面L1-1——L2-2,其中L2-1有两个测试点没过,只有19分
2018 年我们曾经出过一题,是输出“2018 我们要赢”。今年是 2022 年,你要输出的句子变成了“我要赢!就在今天!”然后以比赛当天的日期落款。
本题没有输入。
输出分 2 行。在第一行中输出 I'm gonna win! Today!
,在第二行中用 年年年年-月月-日日
的格式输出比赛当天的日期。已知比赛的前一天是 2022-04-22
。
无
I'm gonna win! Today!
这一行的内容我不告诉你…… 你要自己输出正确的日期呀~
#include
using namespace std;
int main(void)
{
cout << "I'm gonna win! Today!\n";
cout << "2022-04-23\n";
return 0;
}
2019年10月29日,中央电视台专题报道,中国科学院在培育钻石领域,取得科技突破。科学家们用金刚石的籽晶片作为种子,利用甲烷气体在能量作用下形成碳的等离子体,慢慢地沉积到钻石种子上,一周“种”出了一颗 1 克拉大小的钻石。
本题给出钻石的需求量和人工培育钻石的速度,请你计算出货需要的时间。
输入在一行中给出钻石的需求量 N(不超过 107 的正整数,以微克拉
为单位)和人工培育钻石的速度 v(1≤v≤200,以微克拉/天
为单位的整数)。
在一行中输出培育 N 微克拉钻石需要的整数天数。不到一天的时间不算在内。
102000 130
784
作者
陈越
单位
浙江大学
代码长度限制
16 KB
时间限制
400 ms
内存限制
64
#include
using namespace std;
int main(void)
{
int n, v;
cin >> n >> v;
cout << n / v << endl;
return 0;
}
为了保障安静的阅读环境,有些公共图书馆对儿童入馆做出了限制。例如“12 岁以下儿童禁止入馆,除非有 18 岁以上(包括 18 岁)的成人陪同”。现在有两位小/大朋友跑来问你,他们能不能进去?请你写个程序自动给他们一个回复。
输入在一行中给出 4 个整数:
禁入年龄线 陪同年龄线 询问者1的年龄 询问者2的年龄
这里的禁入年龄线
是指严格小于该年龄的儿童禁止入馆;陪同年龄线
是指大于等于该年龄的人士可以陪同儿童入馆。默认两个询问者的编号依次分别为 1
和 2
;年龄和年龄线都是 [1, 200] 区间内的整数,并且保证 陪同年龄线
严格大于 禁入年龄线
。
在一行中输出对两位询问者的回答,如果可以进就输出 年龄-Y
,否则输出 年龄-N
,中间空 1 格,行首尾不得有多余空格。
在第二行根据两个询问者的情况输出一句话:
qing X zhao gu hao Y
,其中 X
是陪同人的编号, Y
是小孩子的编号;huan ying ru guan
;zhang da zai lai ba
;X: huan ying ru guan
,其中 X
是可以入馆的那个人的编号。12 18 18 8
18-Y 8-Y
qing 1 zhao gu hao 2
12 18 10 15
10-N 15-Y
2: huan ying ru guan
#include
using namespace std;
int main(void)
{
int low, up, y1, y2;
cin >> low >> up >> y1 >> y2;
if ( y1 <= low && y2 <= low )
cout << y1 << "-N " << y2 << "-N\n" << "zhang da zai lai ba\n";
else if ( y1 >= low && y2 >= low )
cout << y1 << "-Y " << y2 << "-Y\n" << "huan ying ru guan\n";
else if ( y1 < low && y2 >= up)
cout << y1 << "-Y " << y2 << "-Y\n" << "qing 2 zhao gu hao 1\n";
else if ( y1 >= up && y2 < low )
cout << y1 << "-Y " << y2 << "-Y\n" << "qing 1 zhao gu hao 2\n";
else if ( y1 < low )
cout << y1 << "-N " << y2 << "-Y\n" << "2: huan ying ru guan\n";
else if ( y2 < low )
cout << y1 << "-Y " << y2 << "-N\n" << "1: huan ying ru guan\n";
return 0;
}
你的外星人朋友不认得地球上的加减乘除符号,但是会算阶乘 —— 正整数 N 的阶乘记为 “N!”,是从 1 到 N 的连乘积。所以当他不知道“5+7”等于多少时,如果你告诉他等于“12!”,他就写出了“479001600”这个答案。
本题就请你写程序模仿外星人的行为。
输入在一行中给出两个正整数 A 和 B。
在一行中输出 (A+B) 的阶乘。题目保证 (A+B) 的值小于 12。
3 6
362880
#include
using namespace std;
int main(void)
{
int a, b;
cin >> a >> b;
int sum = 1;
for ( int i = 1; i <= a + b; i ++ ) {
sum *= i;
}
cout << sum << endl;
return 0;
}
我们知道一个骰子有 6 个面,分别刻了 1 到 6 个点。下面给你 6 个骰子的初始状态,即它们朝上一面的点数,让你一把抓起摇出另一套结果。假设你摇骰子的手段特别精妙,每次摇出的结果都满足以下两个条件:
那么你应该可以预知自己第 n 次(1≤n≤5)摇出的结果。
输入第一行给出 6 个骰子的初始点数,即 [1,6] 之间的整数,数字间以空格分隔;第二行给出摇的次数 n(1≤n≤5)。
在一行中顺序列出第 n 次摇出的每个骰子的点数。数字间必须以 1 个空格分隔,行首位不得有多余空格。
3 6 5 4 1 4
3
4 3 3 3 4 3
这 3 次摇出的结果依次为:
6 5 6 6 6 6
5 4 4 5 5 5
4 3 3 3 4 3
#include
using namespace std;
int main(void)
{
int a[6], b[6], n;
fill(b, b + 6, 6);
for ( int i = 0; i < 6; i ++ )
cin >> a[i];
cin >> n;
for ( int i = 0; i < 6; i ++ ) {
b[i] -= n - 1;
}
for ( int i = 0; i < 6; i ++ )
if ( a[i] >= b[i] ) b[i] --;
for ( int i = 0; i < 6; i ++ ) {
if ( i ) cout << ' ';
cout <
上图是新浪微博上的一则趣闻,是瑞典斯德哥尔摩火车上的一道题,看上去是段伪代码:
s = ''
a = '1112031584'
for (i = 1; i < length(a); i++) {
if (a[i] % 2 == a[i-1] % 2) {
s += max(a[i], a[i-1])
}
}
goto_url('www.multisoft.se/' + s)
其中字符串的 +
操作是连接两个字符串的意思。所以这道题其实是让大家访问网站 www.multisoft.se/112358
(注意:比赛中千万不要访问这个网址!!!)。
当然,能通过上述算法得到 112358
的原始字符串 a
是不唯一的。本题就请你判断,两个给定的原始字符串,能否通过上述算法得到相同的输出?
输入为两行仅由数字组成的非空字符串,长度均不超过 104,以回车结束。
对两个字符串分别采用上述斯德哥尔摩火车上的算法进行处理。如果两个结果是一样的,则在一行中输出那个结果;否则分别输出各自对应的处理结果,每个占一行。题目保证输出结果不为空。
1112031584
011102315849
112358
111203158412334
12341112031584
1123583
112358
在 MMORPG《最终幻想14》的副本“乐欲之所瓯博讷修道院”里,BOSS 机工士姆斯塔迪奥将会接受玩家的挑战。
你需要处理这个副本其中的一个机制:N×M 大小的地图被拆分为了 N×M 个 1×1 的格子,BOSS 会选择若干行或/及若干列释放技能,玩家不能站在释放技能的方格上,否则就会被击中而失败。
给定 BOSS 所有释放技能的行或列信息,请你计算出最后有多少个格子是安全的。
输入第一行是三个整数 N,M,Q (1≤N×M≤105,0≤Q≤1000),表示地图为 N 行 M 列大小以及选择的行/列数量。
接下来 Q 行,每行两个数 Ti,Ci,其中 Ti=0 表示 BOSS 选择的是一整行,Ti=1 表示选择的是一整列,Ci 为选择的行号/列号。行和列的编号均从 1 开始。
输出一个数,表示安全格子的数量。
5 5 3
0 2
0 4
1 3
12
#include
using namespace std;
typedef long long ll;
int main(void)
{
ll n, m, q;
cin >> n >> m >> q;
ll t, c;
set row, col;
for ( ll i = 0; i < q; i ++ ) {
cin >> t >> c;
if ( t == 0 ) row.insert(c);
else col.insert(c);
}
ll sum = n * m - (row.size() * m + col.size() * n - row.size() * col.size());
cout << sum << endl;
return 0;
}
天梯赛结束后,某企业的人力资源部希望组委会能推荐一批优秀的学生,这个整理推荐名单的任务就由静静姐负责。企业接受推荐的流程是这样的:
给定全体参赛学生的成绩和他们的 PAT 考试成绩,请你帮静静姐算一算,她最多能向企业推荐多少学生?
输入第一行给出 3 个正整数:N(≤105)为参赛学生人数,K(≤5×103)为企业接受的推荐批次,S(≤100)为该企业的 PAT 面试分数线。
随后 N 行,每行给出两个分数,依次为一位学生的天梯赛分数(最高分 290)和 PAT 分数(最高分 100)。
在一行中输出静静姐最多能向企业推荐的学生人数。
10 2 90
203 0
169 91
175 88
175 0
175 90
189 0
189 0
189 95
189 89
256 100
8
第一批可以选择 175、189、203、256 这四个分数的学生各一名,此外 175 分 PAT 分数达到 90 分的学生和 189 分 PAT 分数达到 95 分的学生可以额外进入名单。第二批就只剩下 175、189 两个分数的学生各一名可以进入名单了。最终一共 8 人进入推荐名单。
#include
using namespace std;
int mt[291];
int main(void)
{
int n, k, s;
cin >> n >> k >> s;
int sky, pat, cnt = 0;
memset(mt, 0, sizeof(mt));
for ( int i = 0; i < n; i ++ ) {
cin >> sky >> pat;
if ( sky >= 175 && pat >= s )
cnt ++;
else mt[sky] ++;
}
int sum = 0;
for ( int i = 175; i < 291; i ++ ) {
if ( mt[i] <= k ) sum += mt[i];
else sum += k;
}
sum += cnt;
cout << sum << endl;
return 0;
}
人造松枝加工场的工人需要将各种尺寸的塑料松针插到松枝干上,做成大大小小的松枝。他们的工作流程(并不)是这样的:
(1)小盒子已经满了,但推送器上取到的松针仍然不满足要求。此时将手中的松枝放到成品篮里,推送器上取到的松针压回推送器,开始下一根松枝的制作。
(2)小盒子中最上面的松针不满足要求,但推送器上已经没有松针了。此时将手中的松枝放到成品篮里,开始下一根松枝的制作。
(3)手中的松枝干上已经插满了松针,将之放到成品篮里,开始下一根松枝的制作。
现在给定推送器上顺序传过来的 N 片松针的大小,以及小盒子和松枝的容量,请你编写程序自动列出每根成品松枝的信息。
输入在第一行中给出 3 个正整数:N(≤103),为推送器上松针片的数量;M(≤20)为小盒子能存放的松针片的最大数量;K(≤5)为一根松枝干上能插的松针片的最大数量。
随后一行给出 N 个不超过 100 的正整数,为推送器上顺序推出的松针片的大小。
每支松枝成品的信息占一行,顺序给出自底向上每片松针的大小。数字间以 1 个空格分隔,行首尾不得有多余空格。
8 3 4
20 25 15 18 20 18 8 5
20 15
20 18 18 8
25 5
#include
using namespace std;
vector hp[1010];
int heap[1010], cnt = 0;
stack st;
int main(void)
{
int n, m, k;
cin >> n >> m >> k;
for ( int i = 0; i < n; i ++ )
cin >> heap[i];
bool flag = false;
for ( int i = 0; i < n; i ++ ) {
if ( hp[cnt].size() == 0 ) {
if ( !st.empty() ) {
hp[cnt].push_back(st.top());
st.pop();
} else {
hp[cnt].push_back(heap[i]);
i ++;
}
if ( i >= n ) break;
}
// for ( int j = i; j < n; j ++ ) {
// if ( j ) cout << " ";
// cout << heap[j];
// }
// cout << endl;
// for ( int j = 0; j < hp[cnt].size(); j ++ )
// cout << hp[cnt][j] << " ";
// cout << endl;
while ( !st.empty() && st.top() <= hp[cnt][hp[cnt].size() - 1] ) {
hp[cnt].push_back(st.top());
st.pop();
if ( hp[cnt].size() == k ) {
flag = false;
break;
}
}
if ( hp[cnt].size() == k ) {
flag = false;
cnt ++;
i --;
continue;
}
if ( heap[i] <= hp[cnt][hp[cnt].size() - 1] ) {
hp[cnt].push_back(heap[i]);
flag = false;
} else if ( st.size() < m ) {
if ( flag == false ) {
st.push(heap[i]);
flag = true;
// continue;
} else {
i --;
cnt ++;
flag = false;
continue;
}
} else if ( st.size() == m ) {
cnt ++;
i --;
flag = false;
}
if ( hp[cnt].size() >= k ) {
flag = false;
cnt ++;
}
// flag = false;
}
while ( !st.empty() ) {
if ( hp[cnt].size() >= k ) cnt ++;
if ( hp[cnt].size() == 0 ) {
hp[cnt].push_back(st.top());
st.pop();
if( st.empty() ) break;
}
while ( !st.empty() && st.top() <= hp[cnt][hp[cnt].size()-1] ) {
hp[cnt].push_back(st.top());
st.pop();
if ( hp[cnt].size() >= k ) cnt ++;
}
if ( !st.empty() && st.top() > hp[cnt][hp[cnt].size()-1] ) cnt ++;
}
for ( int i = 0; i <= cnt; i ++ ) {
if ( hp[cnt].size() == 0 ) break;
for ( int j = 0; j < hp[i].size(); j ++ ) {
if ( j ) cout << " ";
cout << hp[i][j];
}
cout << endl;
}
return 0;
}
新浪微博上有人发了某老板的作息时间表,表示其每天 4:30 就起床了。但立刻有眼尖的网友问:这时间表不完整啊,早上九点到下午一点干啥了?
本题就请你编写程序,检查任意一张时间表,找出其中没写出来的时间段。
输入第一行给出一个正整数 N,为作息表上列出的时间段的个数。随后 N 行,每行给出一个时间段,格式为:
hh:mm:ss - hh:mm:ss
其中 hh
、mm
、ss
分别是两位数表示的小时、分钟、秒。第一个时间是开始时间,第二个是结束时间。题目保证所有时间都在一天之内(即从 00:00:00 到 23:59:59);每个区间间隔至少 1 秒;并且任意两个给出的时间区间最多只在一个端点有重合,没有区间重叠的情况。
按照时间顺序列出时间表中没有出现的区间,每个区间占一行,格式与输入相同。题目保证至少存在一个区间需要输出。
8
13:00:00 - 18:00:00
00:00:00 - 01:00:05
08:00:00 - 09:00:00
07:10:59 - 08:00:00
01:00:05 - 04:30:00
06:30:00 - 07:10:58
05:30:00 - 06:30:00
18:00:00 - 19:00:00
04:30:00 - 05:30:00
07:10:58 - 07:10:59
09:00:00 - 13:00:00
19:00:00 - 23:59:59
#include
using namespace std;
struct tim{
int h1, m1, s1, h2, m2, s2;
}t[100000];
bool cmp(tim a, tim b)
{
if ( a.h1 != b.h1 )
return a.h1 < b.h1;
else if ( a.m1 != b.m1 )
return a.m1 < b.m1;
else
return a.s1 < b.s1;
};
int main(void)
{
int n;
cin >> n;
for ( int i = 0; i < n; i ++ ) {
scanf("%d:%d:%d - %d:%d:%d", &t[i].h1, &t[i].m1, &t[i].s1, &t[i].h2, &t[i].m2, &t[i].s2);
}
sort(t, t + n, cmp);
if ( t[0].h1 != 0 || t[0].m1 != 0 || t[0].s1 != 0 ) {
printf("00:00:00 - %02d:%02d:%02d\n", t[0].h1, t[0].m1, t[0].s1);
}
for ( int i = 0; i < n - 1; i ++ ) {
if ( t[i].h2 != t[i+1].h1 || t[i].m2 != t[i+1].m1 || t[i].s2 != t[i+1].s1 )
printf("%02d:%02d:%02d - %02d:%02d:%02d\n", t[i].h2, t[i].m2, t[i].s2, t[i+1].h1, t[i+1].m1, t[i+1].s1);
}
if ( t[n-1].h2 != 23 || t[n-1].m2 != 59 || t[n-1].s2 != 59 )
printf("%02d:%02d:%02d - 23:59:59\n", t[n-1].h2, t[n-1].m2, t[n-1].s2);
return 0;
}
龙龙是“饱了呀”外卖软件的注册骑手,负责送帕特小区的外卖。帕特小区的构造非常特别,都是双向道路且没有构成环 —— 你可以简单地认为小区的路构成了一棵树,根结点是外卖站,树上的结点就是要送餐的地址。
每到中午 12 点,帕特小区就进入了点餐高峰。一开始,只有一两个地方点外卖,龙龙简单就送好了;但随着大数据的分析,龙龙被派了更多的单子,也就送得越来越累……
看着一大堆订单,龙龙想知道,从外卖站出发,访问所有点了外卖的地方至少一次(这样才能把外卖送到)所需的最短路程的距离到底是多少?每次新增一个点外卖的地址,他就想估算一遍整体工作量,这样他就可以搞明白新增一个地址给他带来了多少负担。
输入第一行是两个数 N 和 M (2≤N≤105, 1≤M≤105),分别对应树上节点的个数(包括外卖站),以及新增的送餐地址的个数。
接下来首先是一行 N 个数,第 i 个数表示第 i 个点的双亲节点的编号。节点编号从 1 到 N,外卖站的双亲编号定义为 −1。
接下来有 M 行,每行给出一个新增的送餐地点的编号 Xi。保证送餐地点中不会有外卖站,但地点有可能会重复。
为了方便计算,我们可以假设龙龙一开始一个地址的外卖都不用送,两个相邻的地点之间的路径长度统一设为 1,且从外卖站出发可以访问到所有地点。
注意:所有送餐地址可以按任意顺序访问,且完成送餐后无需返回外卖站。
对于每个新增的地点,在一行内输出题目需要求的最短路程的距离。
7 4
-1 1 1 1 2 2 3
5
6
2
4
2
4
4
6
人与人之间总有一点距离感。我们假定两个人之间的亲密程度跟他们之间的距离感成反比,并且距离感是单向的。例如小蓝对小红患了单相思,从小蓝的眼中看去,他和小红之间的距离为 1,只差一层窗户纸;但在小红的眼里,她和小蓝之间的距离为 108000,差了十万八千里…… 另外,我们进一步假定,距离感在认识的人之间是可传递的。例如小绿觉得自己跟小蓝之间的距离为 2,则即使小绿并不直接认识小红,我们也默认小绿早晚会认识小红,并且因为跟小蓝很亲近的关系,小绿会觉得自己跟小红之间的距离为 1+2=3。当然这带来一个问题,如果小绿本来也认识小红,或者他通过其他人也能认识小红,但通过不同渠道推导出来的距离感不一样,该怎么算呢?我们在这里做个简单定义,就将小绿对小红的距离感定义为所有推导出来的距离感的最小值。
一个人的异性缘不是由最喜欢他/她的那个异性决定的,而是由对他/她最无感的那个异性决定的。我们记一个人 i 在一个异性 j 眼中的距离感为 Dij;将 i 的“异性缘”定义为 1/maxj∈S(i){Dij},其中 S(i) 是相对于 i 的所有异性的集合。那么“大众情人”就是异性缘最好(值最大)的那个人。
本题就请你从给定的一批人与人之间的距离感中分别找出两个性别中的“大众情人”。
输入在第一行中给出一个正整数 N(≤500),为总人数。于是我们默认所有人从 1 到 N 编号。
随后 N 行,第 i 行描述了编号为 i 的人与其他人的关系,格式为:
性别 K 朋友1:距离1 朋友2:距离2 …… 朋友K:距离K
其中 性别
是这个人的性别,F
表示女性,M
表示男性;K
(
题目保证给出的关系中一定两种性别的人都有,不会出现重复给出的关系,并且每个人的朋友中都不包含自己。
第一行给出自身为女性的“大众情人”的编号,第二行给出自身为男性的“大众情人”的编号。如果存在并列,则按编号递增的顺序输出所有。数字间以一个空格分隔,行首尾不得有多余空格。
6
F 1 4:1
F 2 1:3 4:10
F 2 4:2 2:2
M 2 5:1 3:2
M 2 2:2 6:2
M 2 3:1 2:5
2 3
4
人类喜欢用 10 进制,大概是因为人类有一双手 10 根手指用于计数。于是在千手观音的世界里,数字都是 10 000 进制的,因为每位观音有 1 000 双手 ……
千手观音们的每一根手指都对应一个符号(但是观音世界里的符号太难画了,我们暂且用小写英文字母串来代表),就好像人类用自己的 10 根手指对应 0 到 9 这 10 个数字。同样的,就像人类把这 10 个数字排列起来表示更大的数字一样,ta们也把这些名字排列起来表示更大的数字,并且也遵循左边高位右边低位的规则,相邻名字间用一个点 .
分隔,例如 pat.pta.cn
表示千手观音世界里的一个 3 位数。
人类不知道这些符号代表的数字的大小。不过幸运的是,人类发现了千手观音们留下的一串数字,并且有理由相信,这串数字是从小到大有序的!于是你的任务来了:请你根据这串有序的数字,推导出千手观音每只手代表的符号的相对顺序。
注意:有可能无法根据这串数字得到全部的顺序,你只要尽量推出能得到的结果就好了。当若干根手指之间的相对顺序无法确定时,就暂且按它们的英文字典序升序排列。例如给定下面几个数字:
pat
cn
lao.cn
lao.oms
pta.lao
pta.pat
cn.pat
我们首先可以根据前两个数字推断 pat
< cn
;根据左边高位的顺序可以推断 lao
< pta
< cn
;再根据高位相等时低位的顺序,可以推断出 cn
< oms
,lao
< pat
。综上我们得到两种可能的顺序:lao
< pat
< pta
< cn
< oms
;或者 lao
< pta
< pat
< cn
< oms
,即 pat
和 pta
之间的相对顺序无法确定,这时我们按字典序排列,得到 lao
< pat
< pta
< cn
< oms
。
输入第一行给出一个正整数 N (≤105),为千手观音留下的数字的个数。随后 N 行,每行给出一个千手观音留下的数字,不超过 10 位数,每一位的符号用不超过 3 个小写英文字母表示,相邻两符号之间用 .
分隔。
我们假设给出的数字顺序在千手观音的世界里是严格递增的。题目保证数字是 104 进制的,即符号的种类肯定不超过 104 种。
在一行中按大小递增序输出符号。当若干根手指之间的相对顺序无法确定时,按它们的英文字典序升序排列。符号间仍然用 .
分隔。
7
pat
cn
lao.cn
lao.oms
pta.lao
pta.pat
cn.pat
lao.pat.pta.cn.oms
深度优先搜索与 DFS 序
深度优先搜索算法(DFS)是一种用于遍历或搜索树或图的算法。以下伪代码描述了在树 T 上进行深度优先搜索的过程:
procedure DFS(T, u, L) // T 是被深度优先搜索的树
// u 是当前搜索的节点
// L 是一个链表,保存了所有节点被第一次访问的顺序
append u to L // 将节点 u 添加到链表 L 的末尾
for v in u.children do // 枚举节点 u 的所有子节点 v
DFS(T, v) // 递归搜索节点 v
令 r 为树 T 的根,调用 DFS(T, r, L)
即可完成对 T 的深度优先搜索,保存在链表 L 中的排列被称为 DFS 序。相信聪明的你已经发现了,如果枚举子节点的顺序不同,最终得到的 DFS 序也会不同。
逆序对
给定一个长度为 n 的整数序列 a1,a2,⋯,an,该序列的逆序对数量是同时满足以下条件的有序数对 (i,j) 的数量:
给定一棵 n 个节点的树,其中节点 r 为根。求该树所有可能的 DFS 序中逆序对数量之和。
第一行输入两个整数 n,r(2≤n≤3×105,1≤r≤n)表示树的大小与根节点。
对于接下来的 (n−1) 行,第 i 行输入两个整数 ui 与 vi(1≤ui,vi≤n),表示树上有一条边连接节点 ui 与 vi。
输出一行一个整数,表示该树所有可能的 DFS 序中逆序对数量之和。由于答案可能很大,请对 109+7 取模后输出。
5 3
1 5
2 5
3 5
4 3
24
10 5
10 2
2 5
10 7
7 1
7 9
4 2
3 10
10 8
3 6
516
下图展示了样例 1 中的树。
该树共有 4 种可能的 DFS 序:
因此答案为 6+7+5+6=24。
九条可怜最近在玩一款卡牌游戏。在每一局游戏中,可怜都要使用抽到的卡牌来消灭一些敌人。每一名敌人都有一个初始血量,而当血量降低到 0 及以下的时候,这名敌人就会立即被消灭并从场上消失。
现在,可怜面前有 n 个敌人,其中第 i 名敌人的血量是 ai,而可怜手上只有如下两张手牌:
如果场上还有敌人,等概率随机选中一个敌人并对它造成一点伤害(即血量减 1),重复 K 次。
对所有敌人造成一点伤害,重复该效果直到没有新的敌人被消灭。
下面是这两张手牌效果的一些示例:
现在,可怜先打出了第一张手牌,再打出了第二张手牌。她发现,在第一张手牌效果结束后,没有任何一名敌人被消灭,但是在第二张手牌的效果结束后,所有敌人都被消灭了。
可怜想让你计算一下这种情况发生的概率是多少。
第一行输入两个整数 n,K(1≤n,K≤50),分别表示敌人的数量以及第一张卡牌效果的发动次数。
第二行输入 n 个由空格隔开的整数 ai(1≤ai≤50),表示每个敌人的初始血量。
在一行中输出一个整数,表示发生概率对 998244353 取模后的结果。
具体来说,如果概率的最简分数表示为 a/b(a≥0,b≥1,gcd(a,b)=1),那么你需要输出
a×b998244351mod998244353。
3 2
2 3 3
665496236
在第一张手牌的效果结束后,三名敌人的剩余血量只可能在如下几种中:[1,3,2], [1,2,3], [2,1,3] 和 [2,3,1]。前两种发生的概率是 2/9,后两种发生的概率是 1/9。因此答案为 2/3,输出 2×3998244351mod998244353=665496236。
3 3
2 3 3
776412275
在第一张手牌的效果结束后,三名敌人的剩余血量只可能在如下几种中:[1,2,2]、[2,1,2] 和 [2,2,1]。第一种发生的概率是 2/9,后两种发生的概率是 1/9。因此答案为 4/9,输出 4×9998244351mod998244353=776412275。
5 3
1 4 4 2 5
367353922
12 12
1 2 3 4 5 6 7 8 9 10 11 12
452061016