其实这套cf的题还是比较有趣的,,
689A:Mike and Cellphone
简要题意:
题目中给出了一个手机键盘,之后mike会在键盘上按键,向量相同可被认为是相同按键方式,例如,5 - 8 - 6与 2 - 5 - 3是相同按键方式。题目给出mike的某一个按键序列,判断是否存在冲突
题解:
直接模拟即可,稍微注意一下细节
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
const int maxn = 20;
int ax[maxn], ay[maxn];
int bx[maxn], by[maxn];
int n;
int x;
int cur;
bool check(int x) {
int curx, cury;
if (x >= 1 && x <= 9) {
curx = (x-1) / 3 + 1;
cury = (x-1) % 3 + 1;
} else if (x == 0) {
curx = 4;
cury = 2;
}
for (int i = 2; i <= n; i++) {
curx += bx[i];
cury += by[i];
if (curx >= 1 && curx <= 3 && cury >= 1 && cury <= 3) continue;
if (curx == 4 && cury == 2) continue;
return 0;
}
return 1;
}
int main () {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%1d", &x);
if (i == 1) cur = x;
if (x >= 1 && x <= 9) {
ax[i] = (x-1) / 3 + 1;
ay[i] = (x-1) % 3 + 1;
} else {
ax[i] = 4;
ay[i] = 2;
}
bx[i] = ax[i] - ax[i-1];
by[i] = ay[i] - ay[i-1];
}
for (int i = 1; i <= 9; i++) {
if (i == cur) continue;
if (check(i)) {
printf("NO");
exit(0);
}
}
if (cur != 0 && check(0)) {
printf("NO");
exit(0);
}
printf("YES");
return 0;
}
689B:Mike and Shortcuts
简要题意:
题目中给出一堆点,规定第i点与第j点的距离为(i-j),同时每个点可以穿越到另一个点(不可逆,即a点可以穿越到b点不意味着b点可以穿越到a点),穿越时的花费为1 。求出1号点到其他所有点的最小距离
题解:
貌似我的做法并不是正解,,不过在codeforces强大的评测速度下一切皆有可能。。。直接把相邻的两个点连距离为1的边,把穿越点连距离为1的边,SPFA即可
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
const int maxn = 1000000 + 5000;
int n;
int x;
int last[maxn], pre[maxn], other[maxn], len[maxn];
int tot = 1;
int dis[maxn], que[maxn];
bool vis[maxn];
void add(int x, int y, int z) {
tot++;
pre[tot] = last[x];
last[x] = tot;
other[tot] = y;
len[tot] = z;
}
void spfa(int s) {
memset(dis, 127, sizeof(dis));
que[1] = s;
dis[s] = 0;
int queh = 0, quet = 1;
while (queh != quet) {
queh = (queh + 1) % maxn;
int cur = que[queh];
vis[cur] = 0;
for (int p = last[cur]; p; p = pre[p]) {
int q = other[p];
if (dis[q] > dis[cur] + len[p]) {
dis[q] = dis[cur] + len[p];
if (vis[q] == 0) {
vis[q] = 1;
quet = (quet + 1) % maxn;
que[quet] = q;
}
}
}
}
}
int main () {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &x);
add(i, x, 1);
if (i != 1) {
add(i-1, i, 1);
add(i, i-1, 1);
}
}
spfa(1);
for (int i = 1; i <= n; i++) printf("%d ", dis[i]);
return 0;
}
689C:Mike and Chocolate Thieves
简要题意:
题目中给出4个小偷,他们每个人拿的东西必须是前一个人的k倍,k为正整数。他们的背包容量为n,假设他们有严格m中方案拿东西,求出最小的n值,如果不存在输出-1,m为1015级
题解:
感觉这道题目真的满满的都是套路,给了我一个非常不同寻常的思路提示。。。
- 显然可以发现,题目中的n会随着m的上升不减,所以满足二分性质,
- 每次检查n是否满足题意,显然枚举第一个人取的数量一定会超时,考虑枚举k的值,因为2<=k<=n/a−−−√3<=n√3,对于每一个k,能对答案产生的贡献为⌊nk3⌋,每一步的check即完成
- 上述check的过程要求的是方案数不小于m,最后对ans进行check判断其方案数是否严格等于m,如果是输出,否则-1
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
long long n, m;
long long h, t;
long long mid;
long long ans = -1;
bool check(long long x) {
long long know = 0;
for (int k = 2; k; k++) {
long long p = (long long)k * (long long)k * (long long)k;
if (p < 0) printf("Error");
if (p > x) break;
know += (x / p);
if (know >= m) return 1;
}
return 0;
}
bool check2(long long x) {
long long know = 0;
for (int k = 2; k; k++) {
long long p = (long long)k * (long long)k * (long long)k;
if (p > x) break;
know += (x / p);
}
if (know == m) return 1;
return 0;
}
int main () {
scanf("%I64d", &m);
h = 1ll, t = 1000000000000000000ll;
while (h <= t) {
mid = (h + t) >> 1;
if (check(mid)) {
t = mid - 1;
ans = mid;
} else {
h = mid + 1;
}
}
if (check2(ans)) printf("%I64d", ans);
else printf("-1");
return 0;
}