题目链接:
https://ac.nowcoder.com/acm/contest/3003
A题
思路:
求出三种情况的最多获胜局数即可
代码:
#include<bits/stdc++.h>
using namespace std;
int main() {
#ifdef MyTest
freopen("Sakura.txt", "r", stdin);
#else
ios::sync_with_stdio(false);
cin.tie(0);
#endif
long long a, b, c, x, y, z;
cin >> a >> b >> c >> x >> y >> z;
cout << min(a, y) + min(b, z) + min(c, x);
return 0;
}
B题
思路:
x个1最多组成x个616,y个6最多组成y-1个616;
代码:
#include<bits/stdc++.h>
using namespace std;
int main() {
#ifdef MyTest
freopen("Sakura.txt", "r", stdin);
#else
ios::sync_with_stdio(false);
cin.tie(0);
#endif
int n;
string s;
cin >> n >> s;
int x = 0, y = 0;
for(char & c : s) {
if(c == '1') ++x;
else if(c == '6') ++y;
}
cout << min(y - 1, x);
return 0;
}
C题
思路:
1.在模
m
m
m的情况下,一道题做对的概率是
p
p
p,那么做错的概率是
(
1
−
p
)
%
m
(1-p)\%m
(1−p)%m即
(
1
−
p
+
m
)
%
m
(1-p+m)\%m
(1−p+m)%m;
2.每道题都有做对做错的可能性,设dp[i][j]
为前i
题做对j
题的概率,那么我们很容易可以得到递推式;
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2005;
const ll mod = 1e9 + 7;
ll a[maxn][maxn];
int main() {
#ifdef MyTest
freopen("Sakura.txt", "r", stdin);
#endif
int n;
scanf("%d", &n);
a[0][0] = 1;
for(int i = 1; i <= n; ++i) {
ll p;
scanf("%lld", &p);
for(int j = 0; j < i; ++j) {
a[i][j] = (a[i][j] + a[i - 1][j] * (mod + 1 - p)) % mod;
a[i][j + 1] = (a[i][j + 1] + a[i - 1][j] * p) % mod;
}
}
for(int i = 0; i <= n; i++) {
printf("%lld ", a[n][i]);
}
return 0;
}
D题
思路:
对于平面上三个点A,B,C:
(1)共线,不可以组成三角形;
(2)
∠
B
A
C
\angle BAC
∠BAC为钝角,即
A
B
⃗
⋅
A
C
⃗
<
0
\vec {AB}·\vec {AC}<0
AB⋅AC<0,则可以组成;
(3)
∠
A
B
C
\angle ABC
∠ABC为钝角,即
B
A
⃗
⋅
B
C
⃗
<
0
\vec {BA}·\vec {BC}<0
BA⋅BC<0,则可以组成;
(4)
∠
A
C
B
\angle ACB
∠ACB为钝角,即
C
A
⃗
⋅
C
B
⃗
<
0
\vec {CA}·\vec {CB}<0
CA⋅CB<0,则可以组成;
(5)其余情况则不可以组成钝角三角形;
我们暴力遍历所有点即可;
代码:
#include<bits/stdc++.h>
using namespace std;
int x[505], y[505];
inline bool check(int & a, int & b, int & c) {
if((y[c] - y[a]) * (x[b] - x[a]) == (x[c] - x[a]) * (y[b] - y[a])) return false;
if((x[b] - x[a]) * (x[c] - x[a]) < (y[a] - y[b]) * (y[c] - y[a])) return true;
if((x[a] - x[b]) * (x[c] - x[b]) < (y[b] - y[a]) * (y[c] - y[b])) return true;
if((x[b] - x[c]) * (x[a] - x[c]) < (y[c] - y[b]) * (y[a] - y[c])) return true;
return false;
}
int main() {
#ifdef MyTest
freopen("Sakura.txt", "r", stdin);
#endif
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d %d", x + i, y + i);
int ans = 0;
for(int i = 1; i <= n; i++)
for(int j = i + 1; j <= n; j++)
for(int k = j + 1; k <= n; k++)
if(check(i, j, k)) ++ans;
printf("%d", ans);
return 0;
}
E题
思路:
1.将等式两边平方我们可以得到
i
+
j
+
2
i
j
=
k
i+j+2\sqrt{ij}=k
i+j+2ij=k,因此这里要求
i
∗
j
i*j
i∗j是一个不大于
n
n
n的完全平方数;
2.我们遍历所有小于等于
n
n
n的完全平方数,设
f
(
x
)
f(x)
f(x)为当前遍历到的数
x
x
x的约数个数,则答案为
∑
f
(
x
)
\sum f(x)
∑f(x);
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll get(int n) {
ll ans = 0;
for(int i = 1; i * i <= n; i++) {
if(n % i == 0) {
++ans;
if(i != n / i) ++ans;
}
}
return ans;
}
int main() {
#ifdef MyTest
freopen("Sakura.txt", "r", stdin);
#endif
ll n, ans = 0;
cin >> n;
for(int i = 1; i * i <= n; i++) ans += get(i * i);
cout << ans;
return 0;
}
F题
思路:
一个物品,它对自己的加分是x,对对手的加分是y,那么拿走它,相当于让自己得到x分让对手减少y分,那么对整体的贡献就是x+y分;
因此每个人每次都会选取x+y最大的物品;
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
struct goods {
int id, v;
bool operator < (const goods & g) const {
return v > g.v;
}
}g[maxn];
int n, a[maxn];
int main() {
#ifdef MyTest
freopen("Sakura.txt", "r", stdin);
#endif
scanf("%d", &n);
for(int i = 0; i < n; i++) scanf("%d", a + i);
for(int i = 0; i < n; i++) {
int b;
scanf("%d", &b);
g[i].id = i + 1, g[i].v = a[i] + b;
}
sort(g, g + n);
for(int i = 0; i < n; i += 2) printf("%d ", g[i].id);
putchar('\n');
for(int i = 1; i < n; i += 2) printf("%d ", g[i].id);
return 0;
}
G题
思路:
我们的任务就是判断给定的
a
,
b
,
c
,
d
,
e
,
f
,
g
a,b,c,d,e,f,g
a,b,c,d,e,f,g是否满足
a
d
+
b
e
+
c
f
=
g
a^d+b^e+c^f=g
ad+be+cf=g这个等式;
1.将左边这个等式的值计算出来是不现实的,因为过程变量可能会非常大;
2.因此我们采用取模的想法,将左式的计算在模
p
p
p的情况下计算,此时左式的结果运用快速幂可以迅速求得;
3.我们可以多取几个不同的模以提高判断的准确性;
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a, b, c, d, e, f, g;
ll pow_mod(ll x, ll n, ll mod) {
ll res = 1;
while(n) {
if(n & 1) res = res * x % mod;
x = x * x % mod;
n >>= 1;
}
return res;
}
bool check() {
bool flag = true;
for(ll m = 1e9 + 1; m <= 1e9 + 10; m++) {
ll x = pow_mod(a, d, m);
ll y = pow_mod(b, e, m);
ll z = pow_mod(c, f, m);
if(x + y + z != g) flag = false;
}
puts(flag ? "Yes" : "No");
}
int main() {
#ifdef MyTest
freopen("Sakura.txt", "r", stdin);
#endif
int kase;
for(cin >> kase; kase--;) {
cin >> a >> b >> c>> d >> e >> f >>g;
check();
}
return 0;
}
H题
思路:
我们需要先对序列进行排序;
由贪心的思想我们知道此时一次施法的元素必定是连续的,我们将这些连续的元素看出一个个线段;
设
d
p
[
i
]
dp[i]
dp[i]表示
n
=
=
i
n==i
n==i时的答案(
i
>
=
k
i>=k
i>=k)
则对于第
i
i
i个元素,它有两种选择:
(1)它是一个长度大于k的线段的末尾,它一定接在
i
−
1
i-1
i−1的后面,即
d
p
[
i
]
=
d
p
[
i
−
1
]
+
a
[
i
]
−
a
[
i
−
1
]
dp[i]=dp[i-1]+a[i]-a[i-1]
dp[i]=dp[i−1]+a[i]−a[i−1];
(2)它是一个长度等于k的线段的末尾,即从
i
−
k
+
1
i-k+1
i−k+1到
i
i
i是连续的一段,那么
d
p
[
i
]
=
d
p
[
i
−
k
]
+
a
[
i
]
−
a
[
i
−
k
+
1
]
dp[i]=dp[i-k]+a[i]-a[i-k+1]
dp[i]=dp[i−k]+a[i]−a[i−k+1]
那么
d
p
[
i
]
dp[i]
dp[i]自然是选取这两种情况中的较小值;
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 5;
const long long inf = 1ll << 60;
int n, k;
long long a[maxn], dp[maxn];
int main() {
#ifdef MyTest
freopen("Sakura.txt", "r", stdin);
#endif
scanf("%d %d", &n, &k);
for(int i = 1; i <= n; ++i) scanf("%lld", a + i);
sort(a + 1, a + n + 1);
for(int i = 1; i < k; ++i) dp[i] = inf;
for(int i = k; i <= n; ++i) {
dp[i] = min(dp[i - 1] + a[i] - a[i - 1], dp[i - k] + a[i] - a[i - k + 1]);
}
printf("%lld", dp[n]);
return 0;
}
I题
思路:
首先需要去重,因为权值相同的点互相连接代价为0;
设去重后还剩
n
n
n个;
假设存在
k
(
k
≥
0
)
k(k\geq 0)
k(k≥0),使得二进制的第
k
k
k位,对于所有的权值,存在第
k
k
k位为0的值(
v
i
v_i
vi)且存在第
k
k
k位为1的值(
v
j
v_j
vj),那么我们需要找到最小的
k
k
k,此时所有第
k
k
k位为1的都和
v
i
v_i
vi相连,所有第
k
k
k位为0的都和
v
j
v_j
vj相连,且每次连接的花费为
2
k
2^k
2k;
代码:
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) ((x) & -(x))
int n, v[200005];
int main() {
#ifdef MyTest
freopen("Sakura.txt", "r", stdin);
#endif
scanf("%d", &n);
for(int i = 0; i < n; i++) scanf("%d", v + i);
sort(v, v + n);
int top = unique(v, v + n) - v, x = INT_MAX, y = 0;
for(int i = 0; i < top; i++) {
x &= v[i];
y |= v[i];
}
printf("%lld", (long long)lowbit(x ^ y) * (long long)(top - 1));
return 0;
}
J题
思路:
待补
代码: