传送门:https://ac.nowcoder.com/acm/contest/373#question
A. 翻硬币问题
题解:很明显如果不能一次拿走,那么 B o b Bob Bob总是能翻转其中一枚硬币来破坏 n n n与 m m m的奇偶性。
代码
#include<bits/stdc++.h>
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
using namespace std;
//1 1 1 1 1
//0 0 0 1 1
//0 1 1 1 1
//
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
ios::sync_with_stdio(false); cin.tie(0);
int n,m;
int T;
cin >> T;
while(T--) {
cin >> n >> m;
cout << ((n == m)? "Yes" : "No")<< endl;
}
return 0;
}
B. 666RPG
题意:两个操作。
- 每次将分数加 a [ i ] a[i] a[i]
- 将当前总分乘以 − 1 -1 −1
问:给出序列 a [ i ] a[i] a[i],多少种方案使得最后的分数为 − 666 -666 −666。
题解:
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示前
i
i
i个数可以凑成分数为
j
j
j的方案总数。显然每次有两个状态转移,也就是
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]会从
d
p
[
i
−
1
]
[
j
−
a
[
i
]
]
dp[i-1][j - a[i]]
dp[i−1][j−a[i]]和
d
p
[
i
−
1
]
[
−
j
]
dp[i -1][-j]
dp[i−1][−j]转移过来。因此
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
−
a
[
i
]
]
+
d
p
[
i
−
1
]
[
−
j
]
dp[i][j] = dp[i - 1][j - a[i]] + dp[i -1][-j]
dp[i][j]=dp[i−1][j−a[i]]+dp[i−1][−j]
发现这样会
m
l
e
mle
mle。再看方程,每次只会从
i
−
1
i-1
i−1转移过来,因此,滚动数组解决。
代码
#include<bits/stdc++.h>
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
using namespace std;
typedef long long LL;
const int N = 300 * 666, mod = 1e8 + 7;
LL dp[2][N * 10];
int a[N];
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
ios::sync_with_stdio(false); cin.tie(0);
//dp[i][j] = dp[i - 1][j - a[i]] + dp[i - 1][-j]
int n, cur = 0;
cin >> n;
for(int i = 1; i <= n; ++i) {
cin >> a[i];
}
int dx = N + 666;
dp[1][dx] = 1;
for(int i = 1; i <= n; ++i) {
for(int j = -N; j <= N; ++j) {
if(j == 666) continue;
dp[cur][j + dx] = (dp[cur ^ 1][j - a[i] + dx] + dp[cur ^ 1][-j + dx]) % mod;
}
cur ^= 1;
}
cout << dp[cur ^ 1][-666 + dx] << endl;
return 0;
}
C. 抓捕盗窃犯
题解:可以知道会形成很多个环,在环上任意建一点哨卡即可,最终的收益是环上所有点,因此我们预处理出所有连通块(我这里用的并查集),然后排序取前 m m m大的即可。
代码
#include<bits/stdc++.h>
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
using namespace std;
const int N = 1E5+10;
typedef long long LL;
int f[N],node[N];
LL a[N], sum[N];
vector<int> E[N];
int getf(int v)
{
if(f[v] == v) return v;
return f[v] = getf(f[v]);
}
void mrg(int u,int v)
{
int p = getf(u);
int q = getf(v);
if(p != q) {
f[p] = q;
}
}
vector<LL> value;
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
ios::sync_with_stdio(false); cin.tie(0);
int n,m;
cin >> n >> m;
for(int i = 1; i <= n; ++i) {
cin >> a[i];
f[i] = i;
}
int v;
for(int i = 1; i <= n; ++i) {
cin >> v;
mrg(i,v);
}
for(int i = 1; i <= n; ++i) {
E[getf(i)].push_back(a[i]);
}
LL ans = 0;
for(int i = 1; i <= n; ++i) {
if(f[i] == i) {
LL SUM = 0;
for(auto w : E[i]) {
SUM += w;
}
value.push_back(SUM);
}
}
sort(value.begin(),value.end(),greater<LL>());
for(int i = 0; i < m && i < value.size(); ++i) {
ans += value[i];
}
cout << ans << endl;
return 0;
}
D. 最小相似度
题意:求
m
a
x
{
S
I
M
(
s
i
,
T
)
}
max\{SIM(s_i,T)\}
max{SIM(si,T)}的最小值,
S
I
M
(
A
,
B
)
SIM(A,B)
SIM(A,B)表示
A
A
A和
B
B
B异或后的
0
0
0的个数。
题解:emmmm,表示fwt就做过一道题,不太会。
但是 M M M大小只有 20 20 20,状态只有 2 20 2^{20} 220个,我们考虑给出的 n n n个串到每个状态的距离的最小距离,串 a a a到串 b b b的花费为改变的位数,我们让这个最小距离最大化,然后用 m m m减去这个最大化的最小距离,就是这 n n n个串与串 T T T最大距离的最小值。但是这样做是 O ( n ⋅ 2 m ) O(n\cdot 2 ^ m) O(n⋅2m)的,因此用多源 b f s bfs bfs处理即可,复杂度为节点个数,即 O ( n + 2 m ) O(n + 2^m) O(n+2m)。
代码
#include<bits/stdc++.h>
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
using namespace std;
int dis[1 << 21];
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
ios::sync_with_stdio(false); cin.tie(0);
int n,m;
memset(dis, -1, sizeof dis);
string s;
cin >> n >> m;
queue<int> q;
for(int i = 0; i < n; ++i) {
cin >> s;
int t = 0;
for(int j = 0; j < m; ++j) {
t |= (1 << j) * (s[j] == '1');
}
if(dis[t] == -1) {
dis[t] = 0;
q.push(t);
}
}
int ans = 0;
while(!q.empty()) {
int cur = q.front(); q.pop();
ans = max(ans, dis[cur]);
for(int i = 0; i < m; ++i) {
if(dis[cur ^ (1 << i)] == -1) {
dis[cur ^ (1 << i)] = dis[cur] + 1;
q.push(cur ^ (1 << i));
}
}
}
cout << m - ans << endl;
return 0;
}
E. 球的体积并
题解:正好寒假秦皇岛camp做过一道球的体积交的题,嘿嘿。直接随便copy了一份板子就过了~
判断一下两个球是相交还是相离还是相切即可。
代码
#include<bits/stdc++.h>
using namespace std;
double Pow(double x){ return x*x; }
double san(double x){ return x*x*x; }
const double PI = acos(-1);
struct node {
double x, y, z, r;
void get() { scanf("%lf%lf%lf%lf", &x, &y, &z, &r); }
double dis(node a) {
return sqrt(Pow(x - a.x) + Pow(y - a.y) + Pow(z - a.z));
}
double get_aera(node a) {
double d = dis(a);
double x1 = (a.r * a.r - r * r + d * d) / 2 / d;
double x2 = d - x1;
double h1 = r - x2;
double h2 = a.r - x1;
return PI / 3 * (3 * r - h1) * h1 * h1
+ PI / 3 * (3 * a.r - h2) * h2 * h2;
}
}a[2];
int main() {
a[0].get();
a[1].get();
double ans = 0;
double p = 4.0 / 3 * PI * san(a[1].r), q = 4.0 / 3 * PI * san(a[0].r);
if (a[0].dis(a[1]) <= fabs(a[0].r - a[1].r)) {
ans = max(p, q);
} else if (a[0].dis(a[1]) >= a[0].r + a[1].r) {
ans = p + q;
} else {
ans = p + q - a[0].get_aera(a[1]);
}
printf("%.7f\n", ans);
}