A. Free Ice Cream(Codeforces 686A)
思路
维护一个主人公现有的冰淇淋数量,根据输入的操作动态地增减它就好了。因为每次操作的操作数比较大,所以要注意防溢出。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n, x, opt, num, cnt;
int main() {
scanf("%I64d %I64d\n", &n, &x);
while(n--) {
scanf("%c %I64d\n", &opt, &num);
if(opt == '+') {
x += num;
}
if(opt == '-') {
if(x >= num) {
x -= num;
}
else {
cnt++;
}
}
}
printf("%I64d %I64d\n", x, cnt);
return 0;
}
B. Little Robber Girl’s Zoo(Codeforces 686B)
思路
题目中给的操作实际上可以简化成只交换相邻两个数,这样,通过一系列的交换,就可以将操作转化为我们熟悉的交换任意两个数。然后可以用选择排序的算法——每次选择待排序序列中的最小值,将其放在最低位置——对待排序序列排序。这样的复杂度是 O(n2) ,执行相邻交换的次数也是 O(n2) ,都在允许的范围内。注意:对序列进行排序的时候要对其执行相邻位置交换而不是任意位置交换(虽然实质上是任意位置交换)。
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 110;
int n, m, idx, a[maxn];
void solve(int x, int y) {
for(; y > x; y--) {
swap(a[y-1], a[y]);
printf("%d %d\n", y - 1, y);
}
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
for(int i = 1; i <= n ;i++) {
m = a[i];
idx = i;
for(int j = i + 1; j <= n; j++) {
if(a[j] >= m) {
continue;
}
m = a[j];
idx = j;
}
solve(i, idx);
}
return 0;
}
C. Robbers’ watch(Codeforces 686C)
思路
首先要将输入的两个数转化为
7
进制(实际上根据题意两个数要先自减1),设
代码
#include <bits/stdc++.h>
using namespace std;
int n, m, ln, lm, ans, vis[10];
string sn, sm;
string seven(int n) {
string ans;
for(; n > 0; n /= 7) {
ans.push_back(n % 7);
}
reverse(ans.begin(), ans.end());
return ans;
}
// flag表示前cur-1位数是否都取到上限
void dfs(int cur, int flag) {
if(cur == ln + lm) {
ans++;
return;
}
int ub = 6;
// 若都取到上限则修改本位枚举的上界
if(flag) {
ub = cur < ln ? sn[cur] : sm[cur-ln];
}
for(int i = 0; i <= ub; i++) {
if(!vis[i]) {
int f = 1;
// 计算下一位的flag
if(cur != ln - 1) {
f = flag && i == ub;
}
vis[i] = 1;
dfs(cur + 1, f);
vis[i] = 0;
}
}
}
int main() {
cin >> n >> m;
sn = seven(--n);
sm = seven(--m);
ln = max((int)sn.size(), 1);
lm = max((int)sm.size(), 1);
dfs(0, 1);
cout << ans << endl;
return 0;
}
D. Kay and Snowflake(Codeforces 686D)
思路
对于一个节点
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 10;
int n, q, u, c[maxn], p[maxn], cnt[maxn];
vector <int> G[maxn];
// c[u]表示u点代表的子树的重心
void dfs(int u) {
int maxSon = 0;
cnt[u] = 1;
c[u] = u;
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
dfs(v);
// 动态更新子树节点数量
cnt[u] += cnt[v];
if(cnt[v] > cnt[maxSon]) {
maxSon = v;
}
}
// 如果c[u]不是u的话
if(2 * cnt[maxSon] > cnt[u]) {
int cur = c[maxSon];
// 从儿子的重心开始顺着树链向上寻找c[u]
for(; cnt[u] > 2 * cnt[cur]; cur = p[cur]);
c[u] = cur;
}
}
int main() {
scanf("%d%d", &n, &q);
for(int i = 2; i <= n; i++) {
scanf("%d", &u);
G[u].push_back(i);
p[i] = u;
}
dfs(1);
while(q--) {
scanf("%d", &u);
printf("%d\n", c[u]);
}
return 0;
}
(其他题目略)