World CodeSprint #4[HackerRank]

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值