Codechef June Challenge 2018 Division 2 题解

Naive Chef

Once, after a stressful day, Chef decided to relax and visit a casino near his house to gamble. He feels lucky and he's going to bet almost all of his money.

The game Chef is going to play in the casino consists of tossing a die with NN faces twice. There is a number written on each face of the die (these numbers are not necessarily distinct). In order to win, Chef must get the number AA on the first toss and the number BB on the second toss of the die.

The excited viewers want to know the probability that Chef will win the game. Can you help them find that number? Assume that Chef gets each face of the die with the same probability on each toss and that tosses are mutually independent.

Input

  • The first line of the input contains a single integer TT denoting the number of test cases. The description of TT test cases follows.
  • The first line of each test case contains three space-separated integers NNAA and BB.
  • The second line contains NN space-separated integers x1,x2,,xNx1,x2,…,xN denoting the numbers written on the faces of the die.

Output

For each test case, print a single line containing one real number — the probability that Chef will win. Your answer will be considered correct if its absolute error does not exceed 10610−6.

Constraints

  • 1T701≤T≤70
  • 1N1041≤N≤104
  • 1AN1≤A≤N
  • 1BN1≤B≤N
  • 1xiN1≤xi≤N for each valid ii

Subtasks

Subtask #1 (20 points):

  • T10T≤10
  • N100N≤100

Subtask #2 (80 points): original constraints

Example Input

2
5 1 1
1 1 1 1 1
2 1 1
1 2

Example Output

1.0000000000

0.2500000000

【分析】统计A和B出现的频率,相乘即可。代码
#include<stdio.h>
#include<string.h>
using namespace std;
int cnt[11000];

int main()
{
    int T, n, a, b, i, x;
    double ans;
    scanf("%d", &T);
    while (T--)
    {
        memset(cnt, 0, sizeof(cnt));
        scanf("%d%d%d", &n, &a, &b);
        for (i = 1; i <= n; ++i)
        {
            scanf("%d", &x);
            cnt[x]++;
        }
        printf("%lf\n", (double)cnt[a] / n * cnt[b] / n);
    }
    return 0;
}

Binary Shuffle

Chef has two integers AA and BB. He can perform the following operation on AA an arbitrary number of times (including zero):

  • write AA as a binary number with an arbitrary number of leading zeroes (possibly without any)
  • shuffle the binary digits of AA in an arbitrary way, obtaining a number ss
  • replace AA by s+1s+1

Chef is wondering about the minimum number of operations he has to perform on AA in order to obtain BB. Compute this number or determine that it is impossible.

Input

  • The first line of the input contains a single integer TT denoting the number of test cases. The description of TT test cases follows.
  • The first and only line of each test case contains two space-separated integers AAand BB.

Output

For each test case, print a single line containing one integer — the minimum number of operations or 1−1 if it is impossible to obtain BB from AA.

Constraints

  • 1T1051≤T≤105
  • 0A,B10180≤A,B≤1018

Subtasks

Subtask #1 (20 points): A,B27A,B≤27

Subtask #2 (80 points): original constraints

Example Input

2
2 4
1 5

Example Output

2
1

Explanation

Example case 1: One optimal solution is to not shuffle anything, so Chef just adds 11twice.

Example case 2: We can obtain 55 from 11 in one operation.

分析】根据b的奇偶性以及a和b转为二进制谁含有的1多分开讨论,需要注意,当b为偶数时,需额外考虑二进制b后缀含有几个

连续的0,然后b为1和0需要特判。


代码

#include<stdio.h>
using namespace std;
long long a, b;

int cnt(long long x)
{
    int c = 0;
    while (x)
    {
        if (x % 2 == 1) ++c;
        x /= 2;
    }
    return c;
}

int prez(long long x)
{
    int c = 0;
    while (x)
    {
        if (x % 2 == 0) ++c;
        else break;
        x /= 2;
    }
    return c;
}

int main()
{
    int T, ca, cb, ans, pr;
    scanf("%d", &T);
    while (T--)
    {
        ans = 0;
        scanf("%lld%lld", &a, &b);
        ca = cnt(a);
        cb = cnt(b);
        pr = prez(b);
        if (a == b) printf("0\n");
        else if (b == 0)
        {
            printf("-1\n");
        }
        else if (b == 1)
        {
            if (a == 0) printf("1\n");
            else printf("-1\n");
        } else
        if (b % 2 == 1)
        {
            if (ca == cb) printf("2\n");
            else if (cb > ca) printf("%d\n", cb - ca);
            else printf("2\n");
        }
        else
        {
            if (cb > ca) printf("%d\n", cb - ca + pr);
            else if (ca == cb) printf("%d\n", pr);
            else if (ca == pr + cb - 1) printf("1\n");
            else if (ca > pr + cb - 1) printf("2\n");
            else if (ca < pr + cb - 1) printf("%d\n", pr - ca + cb);
        }
    }
    return 0;
}

Sheokand and String

Sheokand loves strings. Chef has NN strings S1,S2,,SNS1,S2,…,SN which he wants to give to Sheokand; however, he doesn't want to give them away for free, so Sheokand must first correctly answer QQ queries Chef asks him.

In each query, Chef tells Sheokand an integer RR and a string PP. Consider Chef's strings S1S1 through SRSR. Out of these strings, consider all strings such that their longest common prefix with PP is maximum possible. Sheokand should find the lexicographically smallest of these strings.

Sheokand is busy with his exams. Can you solve the queries for him?

Input

  • The first line of the input contains a single integer NN.
  • NN lines follow. For each valid ii, the ii-th of these lines contains Chef's string SiSi.
  • The next line contains a single integer QQ.
  • The following QQ lines describe queries. Each of these lines contains an interger RR, followed by a space and a string PP.

Output

For each query, print a single line containing the string that satisfies the required conditions — the answer to that query.

Constraints

  • 1N100,0001≤N≤100,000
  • 1|Si|101≤|Si|≤10 for each valid ii
  • 1Q100,0001≤Q≤100,000
  • 1RN1≤R≤N
  • 1|P|101≤|P|≤10

Subtasks

Subtask #1 (30 points): 1N,R1,0001≤N,R≤1,000

Subtask #2 (70 points): original constraints

Example Input

4
abcd
abce
abcdex
abcde
3
3 abcy
3 abcde
4 abcde

Example Output

abcd
abcdex
abcde

Explanation

Query 1: For strings S1S1 through S3S3, the longest common prefix is always "abc", but "abcd" is the lexicographically smallest of these three strings.

Query 2: For strings S1S1 through S3S3, the longest common prefix with maximum length is "abcde" and the only string for which it is the LCP is "abcdex", so this is the answer.

Query 3: For strings S1S1 through S4S4, the longest common prefix with maximum length is "abcde"; it is the LCP for strings "abcdex" and "abcde", but "abcde" is the lexicographically smaller string, so it is the answer.

分析

设: s1 为 小于目标串最大的字符串

    s2为 大于等于目标串最小的字符串

对于一个字符串集合,与目标串最长公共前缀达到最长的字符串,一定是s1或s2。考虑到要输出的是字典序最小的字符串,如果是s2,直接输出即可,如果是s1, 那么s1前面可能有最长公共前缀同样长,但是字典序更小的串,但是至多不会超过25个,枚举一下即可。根据题意,不难想到针对queries中的r排序一下,按顺序逐渐将字符串插入到set中,对于每次询问,用lower_bound可以在logn时间内完成查找,再用至多25次枚举找到答案串。

代码

#include<stdio.h>
#include<iostream>
#include<string>
#include<set>
#include<algorithm>
#include<cstring>
using namespace std;

set<string> s;
string ss[110000];
struct jh
{
    int r, id;
    string ans, bj;
}qs[110000];

bool cmp1(jh x, jh y)
{
    return x.r < y.r;
}

bool cmp2(jh x, jh y)
{
    return x.id < y.id;
}

int min(int x, int y)
{
    if (x > y) return y;
    return x;
}

int getcnt(string s, string a)
{
    int i, len = min(s.length(), a.length()), cnt = 0;
    for (i = 0; i < len; ++i)
        if (s[i] == a[i]) ++cnt;
        else break;
    return cnt;
}
int main()
{
    int n, q, i, j, cnt1, cnt2;
    set<string>::iterator si;
    scanf("%d", &n);
    for (i = 1; i <= n; ++i) cin>>ss[i];
    scanf("%d", &q);
    for (i = 1; i <= q; ++i)
    {
        qs[i].id = i;
        cin>>qs[i].r>>qs[i].bj;
    }
    sort(qs + 1, qs + 1 + q, cmp1);
    for (i = 1; i <= q; ++i)
    {
        for (j = qs[i - 1].r + 1; j <= qs[i].r; ++j) s.insert(ss[j]);
        si = s.lower_bound(qs[i].bj);
        if (si == s.begin())
            qs[i].ans = *si;
        else if (si == s.end())
        {
            --si;
            cnt2 = getcnt(*si, qs[i].bj);
            while (si != s.begin() && getcnt(*(--si), qs[i].bj) == cnt2);
            if (si != s.begin()) ++si;
            else if (getcnt(*(si), qs[i].bj) != cnt2) ++si;
            qs[i].ans = *si;
        }
        else
        {
            cnt2 = getcnt(*si, qs[i].bj);
            cnt1 = getcnt(*(--si), qs[i].bj);
            if (cnt2 > cnt1)
            {
                ++si;
                qs[i].ans = *si;
            }
            else
            {
                while (si != s.begin() && getcnt(*(--si), qs[i].bj) == cnt1);
                if (si != s.begin()) ++si;
                else if (getcnt(*(si), qs[i].bj) != cnt1) ++si;
                qs[i].ans = *si;
            }
        }
    }
    sort(qs + 1, qs + 1 + q, cmp2);
    for (i = 1; i <= q; ++i) cout<<qs[i].ans<<endl;
    return 0;
}

Vision

You are given two points PP and QQ and an opaque sphere in a three-dimensional space. The point PP is not moving, while QQ is moving in a straight line with constant velocity. You are also given a direction vector dd with the following meaning: the position of QQ at time ttis Q(t)=Q(0)+dtQ(t)=Q(0)+d⋅t, where Q(0)Q(0) is the initial position of QQ.

It is guaranteed that QQ is not visible from PP initially (at time t=0t=0). It is also guaranteed that PP and QQ do not touch the sphere at any time.

Find the smallest positive time tvtv when QQ is visible from PP, i.e. when the line segment connecting points PP and QQ does not intersect the sphere.

Input

  • The first line of the input contains a single integer TT denoting the number of test cases. The description of TT test cases follows.
  • The first and only line of each test case contains 13 space-separated integers.
    • The first three integers Px,Py,PzPx,Py,Pz denote the coordinates of PP.
    • The next three integers Qx,Qy,QzQx,Qy,Qz denote the initial coordinates of QQ.
    • The next three integers dx,dy,dzdx,dy,dz denote the components of the direction vector dd.
    • The last four integers cx,cy,cz,rcx,cy,cz,r denote the coordinates of the centre of the sphere and its radius.

Output

For each test case, print a single line containing one real number — the time tvtv. Your answer will be considered correct if its absolute or relative error does not exceed 10610−6. It is guaranteed that tvtv exists and does not exceed 109109.

Constraints

  • 1T1051≤T≤105
  • the absolute values of coordinates of all points do not exceed 21092⋅109
  • 1r1091≤r≤109

Subtasks

Subtask #1 (25 points): Pz=Qz=dz=cz=0Pz=Qz=dz=cz=0

Subtask #2 (75 points): original constraints

Example Input

1
3 0 0 -10 -10 0 0 10 0 0 -3 0 3

Example Output

1.0000000000

分析】脑补一下便可得知当某一时刻PQ相见时,之后的时刻PQ都相见。所以直接二分时间,PQ与圆心的距离大于半径即视为相见。

【代码】

#include<cmath>
#include<stdio.h>
using namespace std;

int Px, Py, Pz, Qx, Qy, Qz, dx, dy, dz, cx, cy, cz, cr;
long double l2;
bool cmp(long double l, long double r)
{
    if (r - l > 0.0000001) return 1;
    return 0;
}

long double co(long double m1, long double n1, long double p1, long double m2, long double n2, long double p2)
{
    return abs(m1 * m2 + n1 * n2 + p1 * p2) / sqrt(m1 * m1 + n1 * n1 + p1 * p1) / sqrt(m2 * m2 + n2 * n2 + p2 * p2);
}

long double si(long double m1, long double n1, long double p1, long double m2, long double n2, long double p2)
{
    long double c = co(m1, n1, p1, m2, n2, p2);
    return sqrt(1 - c * c);
}

long double mc(long double x, long double y, long double z)
{
    return sqrt(x * x + y * y + z * z);
}

long double find(long double l, long double r)
{
    long double mid;
    long double nx, ny, nz, m, n, p, d, m1, n1, p1, l1;
    m1 = cx - Px;
    n1 = cy - Py;
    p1 = cz - Pz;
    l2 = mc(m1, n1, p1);
    while (cmp(l, r))
    {
        mid = (l + r) / 2;
        nx = Qx + mid * dx;
        ny = Qy + mid * dy;
        nz = Qz + mid * dz;
        m = nx - Px;
        n = ny - Py;
        p = nz - Pz;
        l1 = mc(m, n, p);
        d = l2 * si(m, n, p, m1, n1, p1);
        if (d > cr) r = mid;
        else l = mid;
    }
    return l;
}



int main()
{
    int T;
    long double ans;
    scanf("%d", &T);
    while (T--)
    {
        scanf("%d%d%d%d%d%d%d%d%d%d%d%d%d", &Px, &Py, &Pz, &Qx, &Qy, &Qz, &dx, &dy, &dz, &cx, &cy, &cz, &cr);
        ans = find(0, 1000000000);
        printf("%Lf\n", ans);
    }
    return 0;
}

Two Flowers

Chef Go has planted a flower field — a grid with nn rows and mm columns. In each cell of this grid, a single flower is planted; let's denote the type of the flower planted in cell (i,j)(i,j)by ai,jai,j.

Today, Chef Go is going to make a new menu with two dishes: Tom Yum Goong and Tom Kha Kai. He needs to pick as many flowers as possible to decorate the dishes and make them look attractive. Each dish can only be decorated with flowers of a single type, so he can only pick flowers of one type or two different types. Also, Chef Go wants the flowers he picks to form one connected area, so that he can finish his job quickly. A connected area is a set of cells such that we can move from any cell to any other cell in this set by only moving between side-adjacent cells from the set.

Help Chef Go find the size of the largest connected area in his flower field which contains at most two types of flowers.

Input

  • The first line of the input contains two space-separated integers nn and mm denoting the size of the field.
  • nn lines follow. For each ii (1in1≤i≤n), the ii-th of these lines contains mm space-separated integers ai,1,ai,2,,ai,mai,1,ai,2,…,ai,m.

Output

Print a single line containing one integer — the maximum number of flowers that can be picked.

Constraints

  • 1n,m2,0001≤n,m≤2,000
  • 1ai,j41061≤ai,j≤4⋅106 for each valid ii and jj
  • the size of the input will be less than 13 MB

Subtasks

Subtask #1 (20 points):

  • 1n,m1001≤n,m≤100
  • 1ai,j1001≤ai,j≤100 for each valid ii and jj

Subtask #2 (20 points):

  • 1n,m1,0001≤n,m≤1,000
  • 1ai,j1061≤ai,j≤106 for each valid ii and jj

Subtask #3 (60 points): original constraints

Example Input

4 5
1 1 2 3 1
3 1 2 5 2
5 2 1 5 6
1 3 1 2 1

Example Output

10

Explanation

One connected area with maximum size consists of the following flowers (flowers marked by dots are not picked):

1 1 2 . .
. 1 2 . .
. 2 1 . .
. . 1 2 1

分析】不会。但是每次提交可以看到每个点的得分情况。然后就乱搞+卡时水过去了。

【代码】

#include<stdio.h>
#include<set>
#include<ctime>
#include<string.h>
using namespace std;

int a[2100][2100], ans, n, m, ta, tot;
bool b[2100][2100], flag[2100][2100];
int he[4100000], y[16100000], totb, z[16100000], cnt[4100000];
set<int> s;

void dfs(int x, int y, int c1, int c2)
{
    ++tot;
    b[x][y] = 1;
    if (x > 1 && !b[x - 1][y] && (c1 == a[x - 1][y] || c2 == a[x - 1][y]) ) dfs(x - 1, y, c1, c2);
    if (x < n && !b[x + 1][y] && (c1 == a[x + 1][y] || c2 == a[x + 1][y]) ) dfs(x + 1, y, c1, c2);
    if (y > 1 && !b[x][y - 1] && (c1 == a[x][y - 1] || c2 == a[x][y - 1]) ) dfs(x, y - 1, c1, c2);
    if (y < m && !b[x][y + 1] && (c1 == a[x][y + 1] || c2 == a[x][y + 1]) ) dfs(x, y + 1, c1, c2);
}

void dfs1(int x, int y)
{
    flag[x][y] = 1;
    if (x > 1 && a[x - 1][y] == a[x][y] && !flag[x - 1][y]) dfs1(x - 1, y);
    if (x < n && a[x + 1][y] == a[x][y] && !flag[x + 1][y]) dfs1(x + 1, y);
    if (y > 1 && a[x][y - 1] == a[x][y] && !flag[x][y - 1]) dfs1(x, y - 1);
    if (y < m && a[x][y + 1] == a[x][y] && !flag[x][y + 1]) dfs1(x, y + 1);
    if (x > 1 && a[x - 1][y] != a[x][y]) s.insert(a[x - 1][y]);
    if (x < n && a[x + 1][y] != a[x][y]) s.insert(a[x + 1][y]);
    if (y > 1 && a[x][y - 1] != a[x][y]) s.insert(a[x][y - 1]);
    if (y < m && a[x][y + 1] != a[x][y]) s.insert(a[x][y + 1]);
}

void mem(int x, int y)
{
    b[x][y] = 0;
    if (b[x - 1][y]) mem(x - 1, y);
    if (b[x + 1][y]) mem(x + 1, y);
    if (b[x][y + 1]) mem(x, y + 1);
    if (b[x][y - 1]) mem(x, y - 1);
}

int main()
{
    clock_t start, end;
    bool plan = 0;
    start = clock();
    int i, j, fans = 0;
    set<int>::iterator si;
    scanf("%d%d", &n, &m);
    for (i = 1; i <= n; ++i)
        for (j = 1; j <= m; ++j) scanf("%d", &a[i][j]);
    for (i = 1; i <= n; ++i)
    {
        for (j = 1; j <= m; ++j)
            if (!flag[i][j])
            {
                end = clock();
                if ((double)(end - start) / CLOCKS_PER_SEC > 3.3)
                {
                    plan = 1;
                    break;
                }
                ans = 0;
                s.clear();
                dfs1(i, j);
                for (si = s.begin(); si != s.end(); si++)
                {
                    tot = 0;
                    dfs(i, j, a[i][j], *si);
                    //        printf("%d %d\n", a[i][j], *si);
                    if (tot > ans) ans = tot;
                    mem(i, j);
                    si++;
                    if (si == s.end()) break;
                }
                tot = 0;
                dfs(i, j, a[i][j], 0);
                if (tot > ans) ans = tot;
                mem(i, j);
                if (ans > fans) fans = ans;
            }
        if (plan) break;
    }
    if (plan)
    {
        memset(flag, 0, sizeof(flag));
        memset(b, 0, sizeof(b));
        fans = 0;
        for (i = 1; i <= n; ++i)
            for (j = 1; j <= m; ++j)
                if (!flag[i][j])
                {
                    ans = 0;
                    s.clear();
                    dfs1(i, j);
                    for (si = s.begin(); si != s.end(); si++)
                    {
                        tot = 0;
                        dfs(i, j, a[i][j], *si);
                        //        printf("%d %d\n", a[i][j], *si);
                        if (tot > ans) ans = tot;
                        //mem(i, j);
                        si++;
                        if (si == s.end()) break;
                    }
                    tot = 0;
                    dfs(i, j, a[i][j], 0);
                    if (tot > ans) ans = tot;
                    //mem(i, j);
                    if (ans > fans) fans = ans;
                }

    }
    printf("%d", fans);
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值