A. Juicer
水题。模拟放橙子的过程,大于尺寸直接跳过。刚开始没太读懂题意,以为是当将要溢出的时候清空,实际上是溢出以后再清空。
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define FIN freopen("in.txt", "r", stdin);
#define FOUT freopen("out.txt", "w", stdout);
#define lson l, mid, cur << 1
#define rson mid + 1, r, cur << 1 | 1
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double ERR = 1e-8;
const int MOD = 1e6 + 3;
const int MAXN = 1e6 + 50;
const int MAXM = 2e5 + 50;
int n, b, d, a[MAXN];
int main() {
#ifdef LOCAL_NORTH
FIN;
#endif // LOCAL_NORTH
while (~scanf("%d%d%d", &n, &b, &d)) {
int cnt = 0, tot = 0;
for (int i = 0; i < n; i++ ) {
scanf("%d", &a[i]);
if (a[i] > b)
continue;
if (tot + a[i] > d) {
cnt++;
tot = 0;
} else {
tot += a[i];
}
}
printf("%d\n", cnt);
}
#ifdef LOCAL_NORTH
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
return 0;
}
B. Checkpoints
暴力。输入的时候计算出所有点的坐标减去初始点的坐标,然后排序。显然访问连续n-1个点要走的总距离最小,所以枚举左端点i,计算出右端点i+n-2,计算出初始点访问[i,i+n-2]需要走的距离。(后来才想起来只可能走[1,n-1]和[2,n]两个区间,枚举都不用了。。。
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define FIN freopen("in.txt", "r", stdin);
#define FOUT freopen("out.txt", "w", stdout);
#define lson l, mid, cur << 1
#define rson mid + 1, r, cur << 1 | 1
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double ERR = 1e-8;
const int MOD = 1e6 + 3;
const int MAXN = 1e6 + 50;
const int MAXM = 2e5 + 50;
int n, a, loc[MAXN];
int main() {
#ifdef LOCAL_NORTH
FIN;
#endif // LOCAL_NORTH
while (~scanf("%d%d", &n, &a)) {
for (int i = 0; i < n; i++) {
scanf("%d\n", &loc[i]);
loc[i] -= a;
}
sort(loc, loc + n);
LL dis = INFLL;
for (int i = 0; i + n - 2 < n; i++) {
if (loc[i] <= 0 && loc[i + n - 2] <= 0) { //当左右端点都在初始点左边
dis = min(dis, (LL)-loc[i]);
} else if (loc[i] <= 0 && loc[i + n - 2] >= 0) { //在左右两边
dis = min(dis, (LL)min(-loc[i] * 2 + loc[i + n - 2], -loc[i] + loc[i + n - 2] * 2)); //注意要返回,所以乘2
} else if (loc[i] >= 0 && loc[i + n - 2] >= 0) { //都在初始点右边
dis = min(dis, (LL)loc[i + n - 2]);
}
}
printf("%I64d\n", dis);
}
#ifdef LOCAL_NORTH
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
return 0;
}
C. Letters Cyclic Shift
既然要去字典序最小,那么显然是变换一个不包含a的连续区间,直接搞就可以了。注意题目要求至少变换一个字符,所以当字符串全是a时,要把最后一位的a变为z。
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define FIN freopen("in.txt", "r", stdin);
#define FOUT freopen("out.txt", "w", stdout);
#define lson l, mid, cur << 1
#define rson mid + 1, r, cur << 1 | 1
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double ERR = 1e-8;
const int MOD = 1e6 + 3;
const int MAXN = 1e6 + 50;
const int MAXM = 2e5 + 50;
string s;
int main() {
#ifdef LOCAL_NORTH
FIN;
#endif // LOCAL_NORTH
while (cin >> s) {
int len = s.size();
bool ok = true;
for (int i = 0; i < len; i++) {
if (ok && s[i] == 'a')
continue;
if (s[i] != 'a') {
s[i]--;
ok = false;
}
else
break;
}
if (ok)
s[len - 1] = 'z';
cout << s << endl;
}
#ifdef LOCAL_NORTH
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
return 0;
}
D. Recover the String
这道题有毒- -
代码写的太乱了,我自己都不想看,说一些思路吧。
题目给出了4个数分别表示原字符串的长度为2的子序列(注意不是子串,不需要连续)的个数,要求还原出字符串。
首先,可以通过a00和a11计算出字符串的0和1的数量(当然计算出的n和m不是整数,就一定是Impossible了),然后就是把n个0和m个1排列组合。
我们可以这样考虑,长度为n,只包含0的字符串,每次插入一个1,那么每次增加的“01”子序列和“10”子序列的总和数一定是n。所以(a01+a10)%n!=0的情况也一定是Impossible。
所以还原字符串就是把1不断地插入到字符串里面。插入的过程就是所有的1都插入到所有的0后面,每插入1个1,“01”子序列的数量就增加n,如果a01%n!=0,那么还需要一个1插入到第(a01%n)个0后面。多余的1全部插入到所有的0前面。
然后就是大量的特判。。。
代码太挫不要看。
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define FIN freopen("in.txt", "r", stdin);
#define FOUT freopen("out.txt", "w", stdout);
#define lson l, mid, cur << 1
#define rson mid + 1, r, cur << 1 | 1
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double ERR = 1e-8;
const int MOD = 1e6 + 3;
const int MAXN = 1e6 + 50;
const int MAXM = 2e5 + 50;
LL a00, a01, a10, a11;
int main() {
#ifdef LOCAL_NORTH
FIN;
#endif // LOCAL_NORTH
while (~scanf("%I64d%I64d%I64d%I64d", &a00, &a01, &a10, &a11)) {
LL zero, one;
if (a00 + a01 + a10 + a11 == 0) {
printf("1\n");
continue;
}
if (!a00 || !a11) {
if (!a00 && !a11) {
if ((!a01 && !a10) || (a01 && a10)) {
printf("Impossible\n");
} else if (a01 <= 1 && !a10) {
printf("01\n");
} else if (!a01 && a10 <= 1) {
printf("10\n");
} else {
printf("Impossible\n");
}
} else if (!a00) {
double t = (1 + sqrt(1 + 8 * a11)) / 2;
if (fabs(t - floor(t)) > ERR) {
printf("Impossible\n");
continue;
}
one = (LL)t;
if (a01 + a10) {
if (a10 + a01 != one) {
printf("Impossible\n");
} else {
for (LL i = 0; i < one; i++) {
if (i == a10)
printf("0");
printf("1");
}
if (one == a10) // 0 0 4 6
printf("0");
puts("");
}
} else {
for (LL i = 0; i < one; i++)
printf("1");
puts("");
}
} else {
double t = (1 + sqrt(1 + 8 * a00)) / 2;
if (fabs(t - floor(t)) > ERR) {
printf("Impossible\n");
continue;
}
zero = (LL)t;
if (a01 + a10) {
if (a01 + a10 != zero) {
printf("Impossible\n");
} else {
for (LL i = 0; i < zero; i++) {
if (i == a01)
printf("1");
printf("0");
}
if (zero == a01) // 6 4 0 0
printf("1");
puts("");
}
} else {
for (LL i = 0; i < zero; i++)
printf("0");
puts("");
}
}
continue;
}
double t = (1 + sqrt(1 + 8 * a00)) / 2;
if (fabs(t - floor(t)) > ERR) {
printf("Impossible\n");
continue;
}
zero = (LL)t;
t = (1 + sqrt(1 + 8 * a11)) / 2;
if (fabs(t - floor(t)) > ERR) {
printf("Impossible\n");
continue;
}
one = (LL)t;
if ((a01 + a10 == 0) || (a10 + a01) % max(zero, one) || (a01 + a10 > zero * one)) {
printf("Impossible\n");
continue;
}
LL rear, pos = -1, head;
if (zero > one) {
rear = min(one, a01 / zero);
if (a01 % zero)
pos = a01 % zero;
head = one - rear - (pos == -1 ? 0 : 1);
for (LL i = 0; i < head; i++)
printf("1");
for (LL i = 0; i < zero; i++) {
printf("0");
if (pos != -1 && i == pos - 1)
printf("1");
}
for (LL i = 0; i < rear; i++)
printf("1");
} else {
rear = min(zero, a10 / one);
if (a10 % one)
pos = a10 % one;
head = zero - rear - (pos == -1 ? 0 : 1);
for (LL i = 0; i < head; i++)
printf("0");
for (LL i = 0; i < one; i++) {
printf("1");
if (pos != -1 && i == pos - 1)
printf("0");
}
for (LL i = 0; i < rear; i++)
printf("0");
}
puts("");
}
#ifdef LOCAL_NORTH
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
return 0;
}
E. Centroids
树形dp。
题目要求判断树上的每一个点,能不能通过至多一次的拆一条边再建一条边(添加之后还是一棵树)操作,使其成为树的重心(树的重心的定义是:以该点为树根,每棵子树的大小都不超过节点数的一半)。
对于一个不是树的重心的节点v,要怎么样操作才能使它成为新树的重心呢?很明显需要在v的节点数大于n/2的子树中,找到一个最大的不超过n/2的子树,把该子树连到v上。这种情况一定是最优的。如果经过一次这样的操作,还有子树大于n/2,那么节点v就要输出0。
所以对于节点v,只需要求出与v相连的子树(v的父节点的不同,详见图E-1)的最大的不超过n/2的子树的大小。具体过程就是3遍dfs。
第一遍dfs,求出每棵子树的大小。
第二遍dfs,求出每棵子树的最大不超过n/2的子树的大小。
第三遍dfs,对于节点v,求出v的父节点pre的不经过v的最大不超过n/2的子树的大小。
(第二、三遍dfs的过程类似于求树的直径,都是利用上一次dfs的结果,来求出v与整棵树的节点的关系)
最后,只需要从1到n枚举v,只要有一棵子树不满足条件,节点v就要输出0(可以理解成:无论怎么拆边与重连,v的某些子树大小都大于n/2)。
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define FIN freopen("in.txt", "r", stdin);
#define FOUT freopen("out.txt", "w", stdout);
#define lson l, mid, cur << 1
#define rson mid + 1, r, cur << 1 | 1
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double ERR = 1e-8;
const int MOD = 1e6 + 3;
const int MAXN = 4e5 + 50;
const int MAXM = 2e5 + 50;
int n;
struct Edge {
int v, nxt;
} E[MAXN << 1];
int Head[MAXN], tot;
void edge_init() {
tot = 0;
memset(Head, -1, sizeof(Head));
}
void edge_add(int u, int v) {
E[tot].v = v;
E[tot].nxt = Head[u];
Head[u] = tot++;
}
int son[MAXN], son_max[MAXN], fa_max[MAXN], par[MAXN];
void dfs(int u, int pre) {
son[u] = 1;
par[u] = pre;
for (int i = Head[u]; ~i; i = E[i].nxt) {
int v = E[i].v;
if (v == pre)
continue;
dfs(v, u);
son[u] += son[v];
}
}
void dfs_down(int u, int pre) {
son_max[u] = (son[u] <= n / 2) ? son[u] : 0;
for (int i = Head[u]; ~i; i = E[i].nxt) {
int v = E[i].v;
if (v == pre)
continue;
dfs_down(v, u);
son_max[u] = max(son_max[u], son_max[v]);
}
}
void dfs_up(int u, int t, int pre) {
fa_max[u] = max(((n - son[u] <= n / 2) ? (n - son[u]) : 0), t);
int max1 = 0, max2 = 0; //最大值与次大值
for (int i = Head[u]; ~i; i = E[i].nxt) {
int v = E[i].v;
if (v == pre)
continue;
int tmp = son_max[v];
if (tmp >= max1)
swap(max1, tmp);
if (tmp >= max2)
swap(max2, tmp);
}
for (int i = Head[u]; ~i; i = E[i].nxt) {
int v = E[i].v;
if (v == pre)
continue;
if (max1 == son_max[v]) //v的子树与max所记录的子树不是同一棵
dfs_up(v, max(fa_max[u], max2), u);
else
dfs_up(v, max(fa_max[u], max1), u);
}
}
int main() {
#ifdef LOCAL_NORTH
FIN;
#endif // LOCAL_NORTH
while (~scanf("%d", &n)) {
edge_init();
for (int i = 0; i < n - 1; i++) {
int u, v;
scanf("%d%d", &u, &v);
edge_add(u, v);
edge_add(v, u);
}
dfs(1, 0);
dfs_down(1, 0);
dfs_up(1, 0, 0);
for (int u = 1; u <= n; u++) {
bool ok = true;
for (int i = Head[u]; ~i; i = E[i].nxt) {
int v = E[i].v;
if (v == par[u]) {
if (n - son[u] - fa_max[u] > n / 2) {
ok = false;
break;
}
} else {
if (son[v] - son_max[v] > n / 2) {
ok = false;
break;
}
}
}
printf("%d%c", ok ? 1 : 0, " \n"[u == n]);
}
}
#ifdef LOCAL_NORTH
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
return 0;
}