链接: https://www.nowcoder.com/acm/contest/204#question
A. 深度学习(思维水题)
题意:
n
n
n 组训练数据,每次训练从
n
n
n 组中随机选出
B
B
B 组,花费
B
B
B 秒,
n
n
n 组数据都被选中过就结束。让你合理设置
B
B
B 使得,使得训练总时间的期望尽可能的小,输出最小期望。
思路: 设置
B
=
n
B = n
B=n ,这样一次就能训练完成,训练总时间
n
n
n ,期望
n
n
n 。因为训练总时间最小等于
n
n
n ,所以这样设置的期望一定最小。
#include <bits/stdc++.h>
using namespace std;
int main(int argc, char const *argv[])
{
int n;
cin>>n;
cout<<n<<endl;
return 0;
}
D. 最小生成树(思维)
题意: 给一个完全无向图,每个点有一个点权
a
i
a_i
ai, 边
(
u
,
v
)
(u, v)
(u,v) 的权值是
a
u
+
a
v
a_u+a_v
au+av, 求边权最小的最小生成树的权值和。
思路: 因为边权取决于点权和,那么一个点和点权最小的点连边,他们的边权(点权和)一定是这个点与所有其他点相连的边权中最小的。那么让所有点都与这个有最小的点权的点相连,生成树的边权就一定是最小的,即
a
n
s
=
(
n
−
2
)
∗
m
i
n
(
a
i
)
+
∑
i
=
1
n
a
i
ans = (n-2)*min(a_i) + \sum _{i=1} ^{n} a_i
ans=(n−2)∗min(ai)+∑i=1nai。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 100100;
int main(int argc, char const *argv[])
{
LL n, a[MAXN];
cin>>n;
for (int i = 0; i < n; ++i) {
cin>>a[i];
}
LL ans = 0;
for (int i = 0; i < n; ++i) {
ans += a[i];
}
ans += (*min_element(a, a+n)) * (n-2);
cout<<ans<<endl;
return 0;
}
I. 连通块计数(组合数学)
题意 : 题面想描述的奇怪的树如下图。我画的这棵树有四条链,每条链有三到四个点。现在给定
n
n
n 条链,每条链上
a
i
a_i
ai 个点,问有多少个非空的连通子树。(结果对
998244353
998244353
998244353 取模)
思路:
1.排除根节点,显然每条链有
C
a
i
+
1
2
C_{a_i+1} ^2
Cai+12 种。可以这样理解,在叶节点加上一条链,算上与根节点连接的链,任取两条切断,得到一种非空子树。
2.加上根节点,每条链都有
a
i
+
1
a_i + 1
ai+1 种切法,每次每条链切一刀都可以组成一种可能,所以共有
∏
i
=
1
n
a
i
+
1
\prod _{i=1} ^{n} a_i+1
∏i=1nai+1 种可能。
综上:
a
n
s
=
∑
i
=
1
n
C
a
i
+
1
2
+
∏
i
=
1
n
a
i
+
1
ans = \sum _{i=1} ^{n} C_{a_i+1} ^2 + \prod _{i=1} ^{n} a_i+1
ans=∑i=1nCai+12+∏i=1nai+1
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 100100;
const int MOD = 998244353;
int main(int argc, char const *argv[])
{
LL n, a[MAXN];
cin>>n;
for (int i = 0; i < n; ++i) {
cin>>a[i];
}
LL ans = 1;
for (int i = 0; i < n; ++i) {
ans *= (a[i] + 1);
ans %= MOD;
}
for (int i = 0; i < n; ++i) {
ans += a[i]*(a[i]+1)/2;
ans %= MOD;
}
cout<<ans<<endl;
return 0;
}
J. 寻找复读机(模拟水题)
题意: 群里有一些人是复读机,这些人每次发的消息一定和上一条消息一样,第一个人一定不是复读机。给你一份聊天记录,让你从小到大输出所有可能是复读机的人的编号。(注意:问的是所有可能的人,一个人没说过话,也可能是复读机)
#include <bits/stdc++.h>
using namespace std;
const int MAXM = 1100;
int main(int argc, char const *argv[])
{
int n, m, num[MAXM];
string s[MAXM];
std::vector<int> v;
cin>>n>>m;
for (int i = 0; i < m; ++i) {
cin>>num[i]>>s[i];
}
for (int i = 1; i <= n; ++i) {
if(i == num[0]) continue;
bool flag = 1;
// int cnt = 0;
for (int j = 1; j < m; ++j) {
if(num[j] == i) {
// cnt++;
if(s[j] != s[j-1]){
flag = 0;
break;
}
}
}
if(flag) v.push_back(i);
}
int len = v.size();
for (int i = 0; i < len; ++i) {
cout<<v[i];
if(i != len-1) cout<<" ";
}
return 0;
}