World CodeSprint #4部分题解。
Minimum Distances
- 题目大意
给N个数,找距离最近的两个数的距离 - 解法
N只有 1e3 , O(N2) 暴力就好了
#include <bits/stdc++.h>
const int N = 1e5 + 10;
int a[N];
int main() {
int n;
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
scanf("%d", a + i);
}
int rlt = n + 1;
for (int i = 0; i < n; ++i)
for (int j = i + 1; j < n && j < i + rlt; ++j)
if (a[i] == a[j]) {
rlt = std::min(rlt, j - i);
break;
}
printf("%d\n", rlt > n ? -1 : rlt);
return 0;
}
Equal Stacks
- 题目大意
有三个栈,你可以分别取走部分值,使得剩下的和最大 - 解法
也是暴力即可,哪边过高就拿那边。
#include <bits/stdc++.h>
const int N = 1e5 + 10;
int a[N];
int b[N];
int c[N];
int main() {
int n, m, h;
scanf("%d%d%d", &n, &m, &h);
for (int i = 0; i < n; ++i) {
scanf("%d", a + i);
}
for (int i = 0; i < m; ++i) {
scanf("%d", b + i);
}
for (int i = 0; i < h; ++i) {
scanf("%d", c + i);
}
int rlt = 0;
for (int i = n - 2; i >= 0; --i)
a[i] += a[i + 1];
for (int i = m - 2; i >= 0; --i)
b[i] += b[i + 1];
for (int i = h - 2; i >= 0; --i)
c[i] += c[i + 1];
int i = 0, j = 0, k = 0;
for (; i < n && j < m && k < h;) {
if (a[i] == b[j] && a[i] == c[k]) {
rlt = a[i];
break;
}
if (a[i] >= b[j] && a[i] >= c[k]) ++ i;
else if (a[i] <= b[j] && b[j] >= c[k]) ++j;
else ++k;
}
printf("%d\n", rlt);
return 0;
}
A or B
- 题目大意
给16进制A,B,C,你有K次机会翻转A和B的二进制中的任意位置,使得 A1xorB1=C ,要求 A1 要尽量小,如果此时有多个答案,再使得 B1 尽量小,最后输出 A1,B1 - 解法
写起来比较麻烦的贪心,首先把A和B中多余的位,必须变成 0 ,
先来一遍必须要处理的位,
- 如果 Ci==0 ,那么对应 Ai,Bi 也要变成0。
- 如果 Ci==1,Ai==0,Bi==0 ,设置 Bi=1 。
如果还有修改机会,然后从高位往低位开始信心,注意每次修改操作的前提都是还有足够修改机会。
- 如果 Ai==1,Bi==1 ,设置成 Ai=0 。
- 如果 Bi==0,Ai==1 ,设置成 Ai=0,Bi=1 ,(两次操作)
#include <bits/stdc++.h>
const int N = 5e4 + 10;
char A[N];
char B[N];
char C[N];
int Abin[N << 2];
int Bbin[N << 2];
int Cbin[N << 2];
inline int hexToBinary(char* src, int dest[]) {
int j = 0;
for (int i = 0; src[i]; ++i, j += 4) {
int key = src[i] - '0';
if (src[i] >= 'A')
key = src[i] - 'A' + 10;
for (int k = 0; k < 4; ++k)
dest[k + j] = (key & (1 << (3 - k))) > 0;
}
std::reverse(dest, dest + j);
return j;
}
inline int countOfOne(int src[], int l, int r) {
int rlt = 0;
for (int i = l; i < r; ++i)
rlt += src[i];
return rlt;
}
inline bool assign(int src[], int idx, int toVal) {
bool rlt = src[idx] > 0;
src[idx] = toVal;
return rlt;
}
inline char computeHex(int src[], int idx) {
int rlt = 0;
for (int i = 0; i < 4; ++i) {
rlt |= src[idx + i] ? 1 << i : 0;
}
return rlt > 9 ? 'A' + rlt - 10 : rlt + '0';
}
inline void binaryToHex(int src[], char dest[]) {
int lastOnePos = 0;
for (int i = N << 2; i; --i) {
if (src[i - 1]) {
lastOnePos = i - 1;
break;
}
}
int hexLen = 0;
for (int i = 0; i <= lastOnePos; i += 4) {
dest[hexLen++] = computeHex(src, i);
}
dest[hexLen] = 0;
std::reverse(dest, dest + hexLen);
}
int main() {
int q, k;
scanf("%d", &q);
for (; q--;) {
memset(Abin, 0, sizeof(Abin));
memset(Bbin, 0, sizeof(Bbin));
scanf("%d%s%s%s", &k, A, B, C);
int Alen = hexToBinary(A, Abin); //二进制长度
int Blen = hexToBinary(B, Bbin);
int Clen = hexToBinary(C, Cbin);
//先计算多余的位并清0
int mustChgInA = countOfOne(Abin, Clen, Alen), mustChgInB = countOfOne(Bbin, Clen, Blen);
for (int i = Clen; i < Alen; ++i)
Abin[i] = 0;
for (int i = Clen; i < Blen; ++i)
Bbin[i] = 0;
//处理必须要变的位
for (int i = 0; i < Clen; ++i) {
if (!Cbin[i]) {
mustChgInA += assign(Abin, i, 0);
mustChgInB += assign(Bbin, i, 0);
} else if (!Abin[i] && !Bbin[i]) {
Bbin[i] = 1;
++mustChgInB;
}
}
int rlt = mustChgInA + mustChgInB;
for (int i = Clen - 1; i >= 0 && rlt < k; --i) {
if (Cbin[i]) {
if (Abin[i] && Bbin[i]) {
++rlt;
Abin[i] = 0;
} else if (Abin[i] && !Bbin[i]) {
if (rlt + 2 <= k) {
rlt += 2;
Abin[i] = 0;
Bbin[i] = 1;
}
}
}
}
if (rlt > k) puts("-1");
else {
binaryToHex(Abin, A);
binaryToHex(Bbin, B);
printf("%s\n%s\n", A, B);
}
}
return 0;
}
Roads in HackerLand
- 题目大意
Given a map of HackerLand, can you help John determine the sum of the minimum distances between each pair of cities? Print your answer in binary representation.
有N个点的图,每条边有权值 2c 且都不相同,求所有点对的最短路径的和的二进制。
- 解法
题目要求所有点对的最短路径之和,要是不小心,N那么大,还想不到办法,不过再看题目描述,发现边非常特殊,所以我们求个最小生成树,所有点对的最短路径,都在这上面了,因为生成树之外的边加进去,两个端点的最短路径,一定不是这条边。
所以求出最小生成树后,再计算每条边的贡献即可得出答案。
#include <bits/stdc++.h>
typedef long long LLONG;
typedef unsigned long long ULLONG;
typedef std::pair<int, std::pair<int, int> >PIPII;
typedef std::pair<int, int>PII;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
PIPII edges[N], treeEdges[N];
int root[N >> 1];
LLONG c[N << 1];
int head[N >> 1], etot;
int sonCount[N >> 1];
inline void addEdge(int u, int v, int w) {
treeEdges[etot] = std::make_pair(head[u], std::make_pair(v, w));
head[u] = etot++;
}
inline void addEdge(const PIPII& edge) {
int u = edge.second.first;
int v = edge.second.second;
int w = edge.first;
addEdge(u, v, w);
addEdge(v, u, w);
}
inline int findSet(int x) {
return root[x] = root[x] == x ? x : findSet(root[x]);
}
inline void unionSet(const PIPII& edge) {
int u = findSet(edge.second.first);
int v = findSet(edge.second.second);
if (u != v) {
root[u] = v;
addEdge(edge);
}
}
inline void dfs(int n, int u, int f) {
for (int e = head[u]; ~e; e = treeEdges[e].first) {
int v = treeEdges[e].second.first;
if (v != f) {
dfs(n, v, u);
sonCount[u] += sonCount[v];
c[treeEdges[e].second.second] += 1LL * (n - sonCount[v]) * sonCount[v];
}
}
}
int main() {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) {
root[i] = i;
sonCount[i] = 1;
head[i] = -1;
}
etot = 0;
memset(c, 0, sizeof(c));
int u, v, w;
for (int i = 0; i < m; ++i) {
scanf("%d%d%d", &u, &v, &w);
edges[i] = std::make_pair(w, std::make_pair(u, v));
}
std::sort(edges, edges + m);
for (int i = 0; i < m; ++i) {
unionSet(edges[i]);
}
dfs(n, 1, -1);
int mx = N << 1;
mx -= 2;
for (int i = 0; i < mx; ++i) {
c[i + 1] += c[i] >> 1;
c[i] &= 1;
}
int lastOnePos = 0;
for (lastOnePos = mx; lastOnePos > 0 && !c[lastOnePos]; --lastOnePos);
for (int i = lastOnePos; i >= 0; --i)
printf("%d", c[i]);
putchar(10);
return 0;
}
Gridland Provinces
- 题目大意
有2*N的格子,每个格子一个字母。主角要从其中一个格子开始向周围移动,要求每个格子至少到达过一次,且时间最短。走完所有格子形成的字符串,有多少种。 - 解法
题目要求至少到达一次,而且要时间最短,那当然是每个格子只走一次了。再看题目,有2*N的格子,所以,我们可以发现,走法只能中间一段用S形走,两端的走到底再返回。这样才能不重复走完。所以我们 O(N2) 枚举中间S形的两个端点再把两端的加上就可以了 - PS数据很强大
- 你得预处理两端的字符串,这样在枚举两个端点时,剩下的可以 O(1) 得出结果
- 有anti-hash…不能用单hash了,得用双hash.
#include <bits/stdc++.h>
typedef long long LLONG;
typedef unsigned long long ULLONG;
typedef std::pair<LLONG, LLONG>PLL;
const int N = 666;
const int MAGIC = 131;
const LLONG MOD[] = {1e9 + 7, 1e9 + 9};
PLL paths[N * N * 4];
ULLONG power[N << 2][2];
char s[2][N];
ULLONG preHash[2][N][2]; //preHash_i,j,k表示从s[i][j]到s[i][1]再到s[i^1][1]到s[i^1][j]同时%MOD[k]
ULLONG suffixHash[2][N][2]; //preHash_i,j,k表示从s[i][j]到s[i][n]再到s[i^1][n]到s[i^1][j]同时%MOD[k]
int toper;
inline int get(int layer, int idx) {
return s[layer][idx];
}
inline void calcPreStr(int layer, int k, int modIdx, ULLONG& answer) {
answer = ((answer * power[k << 1][modIdx]) % MOD[modIdx] + preHash[layer][k][modIdx]) % MOD[modIdx];
}
inline void calcSuffixStr(int layer, int n, int k, int modIdx, ULLONG& answer) {
answer = ((answer * power[(n - k + 1) << 1][modIdx]) % MOD[modIdx] + suffixHash[layer][k][modIdx]) % MOD[modIdx];
}
inline void init(int n) {
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j) {
preHash[i][0][j] = 0;
suffixHash[i][n + 1][j] = 0;
}
for (int i = 1; i <= n; ++i)
for (int j = 0; j < 2; ++j)
for (int k = 0; k < 2; ++k) {
preHash[j][i][k] = (get(j, i) * power[(i - 1) << 1][k] + preHash[j][i - 1][k]) % MOD[k];
preHash[j][i][k] = (preHash[j][i][k] * MAGIC + get(j ^ 1, i)) % MOD[k];
}
for (int i = n; i > 0; --i)
for (int j = 0; j < 2; ++j)
for (int k = 0; k < 2; ++k) {
suffixHash[j][i][k] = (get(j, i) * power[(n - i) << 1][k] + suffixHash[j][i + 1][k]) % MOD[k];
suffixHash[j][i][k] = (suffixHash[j][i][k] * MAGIC + get(j ^ 1, i)) % MOD[k];
}
}
inline void addColumn(ULLONG& rlt, int layer, int p, int modIdx) {
rlt = (rlt * MAGIC % MOD[modIdx] + get(layer, p)) % MOD[modIdx];
rlt = (rlt * MAGIC % MOD[modIdx] + get(layer ^ 1, p)) % MOD[modIdx];
}
inline void calcLtoR(int p, int n, int layer) {
ULLONG answer[2] = {0};
for (int i = 0; i < 2; ++i) {
calcPreStr(layer ^ 1, p - 1, i, answer[i]);
}
for (int j = p; j <= n; ++j, layer ^= 1) {
ULLONG tmpAnswer[2];
for (int i = 0; i < 2; ++i) {
tmpAnswer[i] = answer[i];
calcSuffixStr(layer, n, j, i, tmpAnswer[i]);
addColumn(answer[i], layer, j, i);
}
paths[toper++] = std::make_pair(tmpAnswer[0], tmpAnswer[1]);
}
}
inline void calcRtoL(int p, int n, int layer) {
ULLONG answer[2] = {0};
for (int i = 0; i < 2; ++i) {
calcSuffixStr(layer ^ 1, n, p + 1, i, answer[i]);
}
for (int j = p; j > 0; --j, layer ^= 1) {
ULLONG tmpAnswer[2];
for (int i = 0; i < 2; ++i) {
tmpAnswer[i] = answer[i];
calcPreStr(layer, j, i, tmpAnswer[i]);
addColumn(answer[i], layer, j, i);
}
paths[toper++] = std::make_pair(tmpAnswer[0], tmpAnswer[1]);
}
}
int main() {
power[0][0] = 1;
power[0][1] = 1;
for (int i = 1; i - N < (N << 1); ++i) {
for (int j = 0; j < 2; ++j) {
power[i][j] = (power[i - 1][j] * MAGIC) % MOD[j];
}
}
int t, n;
scanf("%d", &t);
for (; t--;) {
scanf("%d%s%s", &n, s[0] + 1, s[1] + 1);
init(n);
toper = 0;
for (int i = 1; i <= n; ++i) {
calcLtoR(i, n, 0);
calcLtoR(i, n, 1);
calcRtoL(i, n, 0);
calcRtoL(i, n, 1);
}
std::sort(paths, paths + toper);
int tot = std::unique(paths, paths + toper) - paths;
printf("%d\n", tot);
}
return 0;
}