【问题标题】:Codechef KCHAR wrong answerCodechef KCHAR 错误答案
【发布时间】:2023-03-16 02:12:01
【问题描述】:

最近我正在解决以下problem on codechef

爱丽丝最近和大厨吵架了。所以 Chef 给 Alice 一个问题。 最初,您会得到一个空字符串,并且可以进行两次操作。

Operation-1:每个“a”变成“c”,每个“c”变成“a”。例如,“acc”变为“caa”。
Operation-2: 字符串反转。例如,“acc”变成“cca”。

厨师给出以下生成方程 SN = SN-1 + "a" + Operation-1(Operation-2(SN-1))

其中 S0 = ""(空字符串)。

Alice 很容易找出接下来的几个序列:

S1 = "a"
S2 = "aac"
S3 = "aacaacc"

现在 Chef 要求查找 SLOC 的第 K 个字符,其中 LOC = 102017。你需要帮助爱丽丝找到答案。

1 ≤ T ≤ 100
1≤K≤1018

我已尝试使用以下代码解决问题:

scanf("%lld",&t);
while(t--)
{
    scanf("%lld",&k);
    count=0;
    while(1)
    {
        lg=(double)log(k)/log(2);
        av=pow(2,lg);
        if(av!=k)
        {
            diff=k-av;
            k=av-diff;
            count++;
        }
        else
        {
            if(count%2==0)
            {
                printf("a\n");
            }
            else
            {
                printf("c\n");
            }
            break;
        }
    }       

}

解决方案有什么问题?

我尝试了各种输入并得到了正确答案,但是当我提交时我得到了 WA。谁能提供一些解决方案失败的测试用例。

【问题讨论】:

  • 您检查过大 k 的数值不准确吗?对于大 k 来说,它似乎不太可能完全等于 pow(2, double(log(k)/log(2)))
  • 例如当k是1ULL<<29
  • 是的,即使 k=10^18 也给出了正确的答案
  • 另外——你的代码不完整。 diff和av的类型有哪些?
  • 我只分享了一段代码。所有变量都是 long long int

标签: algorithm


【解决方案1】:

您的代码不适用于k=576460752303423478。它不会终止。我还没有完全调试它,但根本原因是数值不准确:av 应该是小于或等于k 的 2 的最大幂,但它最终大于k。我预计还有其他情况会终止但会产生错误的结果。

为了找到失败的案例,我编写了自己的代码版本,并尝试针对k 的许多值对其进行测试。那没有任何结果,所以然后尝试了接近 2 的幂。那找到了上面的例子。

这是找到问题案例的代码(这里x() 是您的代码,y() 是我的代码)。我在您的代码中添加了 asserts 来演示问题,但您可以删除它们并看到代码不会终止。

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

char x(long long int k) {
    long long int count=0;
    while(1) {
        long long int lg=(double)log(k)/log(2);
        long long int av=pow(2,lg);
        assert((av & (av-1)) == 0); // av is a power of 2
        assert(av <= k);  // ... that's at most k
        if(av!=k) {
            long long int diff=k-av;
            k=av-diff;
            count++;
        } else {
            if(count%2==0) return 'a';
            return 'c';
        }
    }
}

char y(long long int k) {
    int count = 0;
    long long int j = 1;
    while(j < k) j *= 2;
    while (1) {
        if (j == k) {
            return count % 2 ? 'c' : 'a';
        } else if (k > j) {
            k = 2*j-k;
            count += 1;
        }
        j >>= 1;
    }
}

int main(int argc, char **argv) {
    int t = 60;
    while(t--) {
        for (int k = -10; k < 10; k++) {
            long long int r = (1LL<<t) + k;
            if (r <= 0) continue;
            printf("%lld\n", r);
            printf("y: %c\n", y(r));
            printf("x: %c\n", x(r));
            if (x(r) != y(r)) exit(1);
        }
    }
    return 0;
}

【讨论】:

    【解决方案2】:

    虽然@PaulHankin 解释了你的解决方案出了什么问题

    这是我接受的用 C++14 编写的解决方案

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    
    LL k;
    int T;
    string f(int N, LL K){
        LL len = (1LL<<N)-1;
        LL pLen = (1LL<<(N-1)) - 1;
        if(K == len/2 + 1LL) return "a";
        if(K == len - pLen/2) return "c";
        return f(N-1, K < len/2+1LL? K : K-len/2-1LL);
    }
    
    int main() {
        cin >> T;
        while(T--){
            cin >> k;
            cout << f(60, k) << endl;
        }
        return 0;
    }
    

    我的解决方案基于以下主要观察结果:

    1. S_n = S_(n-1) + "a" + REPLACE(S_(n-1), mid_point, "c")
    2. K &lt;= 10^18 表示n &lt;= 60,其长度足以覆盖所有Ks
    3. 基于1,对于每个n,有两个特殊的位置,你知道S_n的答案:

      3a。 Len(S_n)/2 + 1(中间点,必须是"a"

      3b。 Len(S_n) - Len(S_(n-1))/2(即3/4四分位点,必须是"c"

    那么算法很简单:看看K是不是当前S_n的特殊位置,如果是我们就找到了答案;否则答案等于在S_(n-1)中搜索相对位置K'

    【讨论】:

      【解决方案3】:

      您可以尝试这样做,而不是按照 shole 的回答每次执行 60 次迭代:

      N = ceil(log(k)/log(2)); 
      

      第一次迭代。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-11-12
        • 2019-05-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-28
        • 2020-02-12
        相关资源
        最近更新 更多