A
题意:
n
n
瓶药里面有一瓶生药,每次会选择瓶给兔子服用,只有这
k
k
瓶中有该生药,这个兔子才不会死。问最坏的情况下最少要死多少只兔子才可以确定哪一瓶是生药。
思路:推推就会发现和有关, 特判 n=k n = k 和 k=1 k = 1 的情况
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <queue>
using namespace std;
typedef long long LL;
int main()
{
int n, k; scanf("%d%d", &n, &k);
if(n == k) {
if(n == 1) {
printf("0\n");
}
else {
printf("-1\n");
}
}
else {
if(k == 1) {
printf("%d\n", n - 1);
}
else if(n % k == 0 || n % k == 1) {
printf("%d\n", n / k);
}
else {
printf("%d\n", n / k + 1);
}
}
return 0;
}
B
题意:给定两个只有小写字母的相等的字符串,每次从两个字符串中分别取出一个字母(直到取完为止),问取出相等字母次数的期望。
思路:概率论的知识,但我是猜的结果。原谅我数学知识全还给老师了……
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <queue>
using namespace std;
typedef long long LL;
char str[200000 + 10];
int num[30];
int main()
{
scanf("%s", str);
int len = strlen(str);
memset(num, 0, sizeof(num));
for(int i = 0; i < len; i++) {
num[str[i] - 'a']++;
}
double ans = 0;
for(int i = 0; i < 26; i++) {
ans += num[i] * 1.0 / len * num[i];
}
printf("%.15lf\n", ans);
return 0;
}
C
没写
D
题意:从
n
n
个人选出若干个,构成两个非空集合,一个集合送礼物,另一个集合接受礼物。问方案数。
思路:
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <queue>
using namespace std;
typedef long long LL;
const int MAXN = 200000 + 10;
const int MOD = 1e9 + 9;
void add(LL &x, LL y) { x += y; if(x >= MOD) x -= MOD; }
LL f[MAXN], s[MAXN];
LL pow_mod(LL a, int n) {
LL ans = 1;
while(n) {
if(n & 1) {
ans = ans * a % MOD;
}
a = a * a % MOD;
n >>= 1;
}
return ans;
}
LL C(int n, int m) {
return f[n] * pow_mod(f[m], MOD - 2) % MOD * pow_mod(f[n - m], MOD - 2) % MOD;
}
LL Work(LL n) {
if(n < 0) {
n += MOD;
}
return n;
}
int main()
{
int n; scanf("%d", &n);
f[0] = 1; s[0] = 1;
for(int i = 1; i <= n; i++) {
f[i] = f[i - 1] * i % MOD;
s[i] = s[i - 1] * 2 % MOD;
}
LL ans = 0;
for(int i = 2; i <= n; i++) {
add(ans, C(n, i) * Work(s[i] - 2) % MOD);
}
printf("%lld\n", ans);
return 0;
}
E
题意:问你两个图是否存在相同的最短路径。
解法一:对每个图跑一次BFS,再把两个图合起来再跑一次BFS,最后
check
c
h
e
c
k
一下
解法二:对每个跑一次BFS,然后总的
check
c
h
e
c
k
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <queue>
using namespace std;
typedef long long LL;
struct Node {
int x, y;
Node() {}
Node(int a, int b) : x(a), y(b) {}
};
char str[2][502][502];
int dis[2][502][502];
int n, m;
bool judge(int id, Node a) {
if(a.x < 0 || a.x >= n) return false;
if(a.y < 0 || a.y >= m) return false;
if(dis[id][a.x][a.y] != -1) return false;
if(str[id][a.x][a.y] == '#') return false;
return true;
}
int ne[4][2] = {0,1, 0,-1, 1,0, -1,0};
Node p, q;
queue<Node> Q;
void BFS(int id) {
Q.push(Node(0, 0)); dis[id][0][0] = 0;
while(!Q.empty()) {
p = Q.front(); Q.pop();
if(p.x == n - 1 && p.y == m - 1) {
continue;
}
for(int i = 0; i < 4; i++) {
q = Node(p.x + ne[i][0], p.y + ne[i][1]);
if(judge(id, q)) {
dis[id][q.x][q.y] = dis[id][p.x][p.y] + 1;
Q.push(q);
}
}
}
}
bool d[502][502];
void Check() {
memset(d, false, sizeof(d));
Q.push(Node(0, 0)); d[0][0] = true;
while(!Q.empty()) {
p = Q.front(); Q.pop();
if(p.x == n - 1 && p.y == m - 1) {
printf("YES\n");
return;
}
for(int i = 0; i < 4; i++) {
q = Node(p.x + ne[i][0], p.y + ne[i][1]);
if(q.x < 0 || q.x >= n || q.y < 0 || q.y >= m || d[q.x][q.y]) {
continue;
}
bool flag = true;
for(int j = 0; j < 2; j++) {
if(dis[j][q.x][q.y] != dis[j][p.x][p.y] + 1) {
flag = false;
break;
}
}
if(flag) {
d[q.x][q.y] = true;
Q.push(q);
}
}
}
printf("NO\n");
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++) {
scanf("%s", str[0][i]);
}
for(int i = 0; i < n; i++) {
scanf("%s", str[1][i]);
}
memset(dis, -1, sizeof(dis));
BFS(0); BFS(1), Check();
return 0;
}
F
题意:
n
n
个人和个避难所在一条直线上,每个避难所可以容纳
k
k
个人。现在有秒时间,最多多少人获救。
思路:从前向后贪心即可。
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 200000 + 10;
int a[MAXN], b[MAXN];
int main()
{
int n, m, k, t; scanf("%d%d%d%d", &n, &m, &k, &t);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
for(int i = 1; i <= m; i++) {
scanf("%d", &b[i]);
}
sort(a + 1, a + n + 1);
sort(b + 1, b + m + 1);
int ans = 0;
int now = 1, use = k;
for(int i = 1; i <= n && now <= m; i++) {
while(now <= m && b[now] <= a[i]) {
if(a[i] - b[now] <= t && use) {
break;
}
now++; use = k;
}
if(use == 0) {
now++; use = k;
}
if(now <= m) {
if(b[now] <= a[i]) {
if(a[i] - b[now] <= t && use) {
ans++; use--;
}
}
else {
if(b[now] - a[i] <= t && use) {
ans++; use--;
}
}
}
}
printf("%d\n", ans);
return 0;
}
G
没写
H
题意:给定两个由三个点组成的三角形,问是否相似。
思路:算出边长的平方,比较即可。
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <queue>
using namespace std;
typedef long long LL;
LL x[6], y[6];
LL d[6];
LL Dis(int i, int j) {
return (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]);
}
bool Check() {
int cnt = 0;
for(int i = 0; i < 2; i++) {
for(int j = i + 1; j < 3; j++) {
d[cnt++] = Dis(i, j);
}
}
for(int i = 3; i < 5; i++) {
for(int j = i + 1; j < 6; j++) {
d[cnt++] = Dis(i, j);
}
}
sort(d, d + 3);
sort(d + 3, d + 6);
return d[0] * d[4] == d[1] * d[3] && d[0] * d[5] == d[2] * d[3];
}
int main()
{
for(int i = 0; i < 6; i++) {
scanf("%lld%lld", &x[i], &y[i]);
}
printf(Check() ? "YES\n" : "NO\n");
return 0;
}
I
没写
J
题意:
n
n
张牌,个洗牌机,问你能否将牌
x
x
洗到第一个位置。
思路:建一个有向图,然后DFS即可。
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 200000 + 10;
int n, m;
int a[MAXN];
bool vis[MAXN];
vector<int> G[MAXN];
bool Check(int u) {
if(u == 1) {
return true;
}
vis[u] = true;
for(int i = 0; i < (int)G[u].size(); i++) {
int v = G[u][i];
if(vis[v]) continue;
if(Check(v)) {
return true;
}
// vis[v] = false;
}
return false;
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
vis[i] = false; G[i].clear();
}
scanf("%d", &m);
for(int i = 1; i <= m; i++) {
for(int j = 1; j <= n; j++) {
int v; scanf("%d", &v);
G[v].push_back(j);
}
}
int pos; scanf("%d", &pos);
for(int i = 1; i <= n; i++) {
if(a[i] == pos) {
pos = i;
break;
}
}
printf(Check(pos) ? "YES\n" : "NO\n");
return 0;
}
K
题意:个发射端,
n
n
个接收端。发射的都是直线,若直线交叉一次释放一焦耳能量。让你制定一个发射序列,使得正好释放焦耳能量。
思路:其实就是一个逆序对。
证明一下:
假设当前发射端为
i
i
,发射序列为。对于后面的发射序列元素
a[j](j>i)
a
[
j
]
(
j
>
i
)
,若
a[j]>a[i]
a
[
j
]
>
a
[
i
]
,那么这两条发射线一定不会相交;反之必定相交。
这样就相当于求解每个元素后面有多少个元素比它大,也就是逆序对。
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 200000 + 10;
int a[MAXN];
int main()
{
int n; LL k; scanf("%d%lld", &n, &k);
int Max = n;
int val = 1;
int i, j, num = n - 1;
for(i = 1; i <= n; i++, num--) {
if(k >= num) {
a[i] = Max;
k -= num;
Max--;
}
else {
a[i] = val;
val++;
}
}
for(i = 1; i <= n; i++) {
if(i > 1) printf(" ");
printf("%d", a[i]);
}
printf("\n");
return 0;
}
L
题意:构造回文串。
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <queue>
using namespace std;
typedef long long LL;
const int MAXN = 200000 + 10;
char str[MAXN];
int main()
{
scanf("%s", str);
int len = strlen(str);
for(int i = 0; i < len / 2; i++) {
if(str[i] != str[len - i - 1]) {
str[i] = str[len - i - 1];
}
}
printf("%s\n", str);
return 0;
}
M
题意:
f(x) = θ(s1∗x − a1) + θ(s2∗x − a2) + ... + θ(sn∗x − an)
f
(
x
)
=
θ
(
s
1
∗
x
−
a
1
)
+
θ
(
s
2
∗
x
−
a
2
)
+
.
.
.
+
θ
(
s
n
∗
x
−
a
n
)
,其中
θ(x)={0x<01x>=0
θ
(
x
)
=
{
1
x
>=
0
0
x
<
0
,每次给出一个
x
x
,查询结果。
思路:根据 s s 为和 1 1 的情况,把序列分成两个集合,然后二分即可。
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 200000 + 10;
int a[MAXN], b[MAXN];
int main()
{
int n; scanf("%d", &n);
int la = 0, lb = 0;
for(int i = 1; i <= n; i++) {
int s, v;
scanf("%d%d", &s, &v);
if(s == 1) {
a[la++] = v;
}
else {
b[lb++] = v;
}
}
sort(a, a + la); sort(b, b + lb);
int m; scanf("%d", &m);
while(m--) {
int v; scanf("%d", &v);
int ans1;
if(a[la - 1] <= v) {
ans1 = la;
}
else {
ans1 = upper_bound(a, a + la, v) - a;
}
v = -v;
int ans2;
if(b[lb - 1] <= v) {
ans2 = lb;
}
else {
ans2 = upper_bound(b, b + lb, v) - b;
}
printf("%d\n", ans1 + ans2);
}
return 0;
}