2015-03-25 69 views
0

下面是一个问题:我们只需要计算由0和1组成的字符串中的101个数。 101是字符串的任何子序列。计数字符串中的101个数

例如:10101其中有4个101。

我很确定我正确地解决了它。对于每个零,我预先计算1之前和之后的数字,然后乘以答案,然后将结果添加到res。

的代码是给我长的字符串组成的测试用例错误的答案1000000

我想知道哪里是我的代码的问题?

输入测试用例:https://he-s3.s3.amazonaws.com/media/hackathon/nitcencode03/problems/p1-6/d434839c-d-input-d4340a6.txt?Signature=IXEy0YlTGPX%2FkjsGoc%2FRxCC8bG8%3D&Expires=1427265583&AWSAccessKeyId=AKIAJLE6MUHDYS3HN6YQ

输出768,16是,但我的代码是给

这里是我的代码:

char s[1000005]; 

unsigned long long ans, res, a[1000005]; 

int main() 
{ 
    int n; 

    scanf("%s", s); 
    n = strlen(s); 

    a[0] = 0; res = 0; 
    for(int i = 1;i <= n;++i) 
     a[i] = a[i - 1] + (s[i - 1] == '1'); 

    for(int i = 1;i <= n;++i) 
     if(s[i - 1] == '0') { 
      ans = a[n] - a[i]; 
      ans *= a[i - 1]; 
      res += ans; 
      //if(ans < 0 || res < 0) printf("%lld %lld\n", ans, res); 
     } 

    printf("%llu\n", res); 


    return 0; 
} 
+0

1.您的输入缓冲器()''可能截断的输入端。更好地从文件中读取输入字符串。 (或使用该文本输入时出现其他问题)。 2.如果你使用''stdint.h''或''cstdint''头文件和类型如''uint64_t''而不是非便携式的''unsigned long long'',那么你不会感到惊讶。 – BitTickler 2015-03-25 06:27:46

+0

我使用cin >> s在C++中尝试了相同的代码,其中s是一个字符串,它给出了相同的结果。我不明白为什么scanf可能会截断输入? – Chadi 2015-03-25 08:06:24

+0

你在哪里提出逻辑总结'1'和'0'来得到答案?逻辑看起来有缺陷,或者发布的答案有缺陷。在'868789'字符串中有'434105''''''',''434684''''','868789'字符串,根据你的代码给出了'868206'作为答案,同时看着你发布的答案: '18446708952791232852'这只是有点害羞溢出未签名的长长的MAX。我认为你的方程式是可疑的。 – 2015-03-25 08:19:38

回答

0

花一点后时间排除了有关适当存储类型,gcc代码/内存模型以及升级/溢出的各种问题问题,我想我已经找到了一个我对这个问题满意的方法。

随着数据的大小,默认的代码/内存模型很好。存储在a阵列中的值完全在unsigned类型内,允许静态声明a[1000000]工作而不会导致段错误。 (4M存储要求)

结果值符合unsigned long(x86_64)或unsigned long long(x86)。但是,如果结果计算未被转换为unsigned long,则会存在一个微妙的问题,因为这两项中的任何一项都不会导致升级。

就这样,我想我会这种方式发布到的情况下,任何解决方案还有很好奇:

#include <stdio.h> 

#define LMAX 868800 

int main (int argc, char **argv) { 

    if (argc < 2) { 
     fprintf (stderr, "Error: insufficient input, usage: %s <filename>\n", argv[0]); 
     return 1; 
    } 

    char s[LMAX] = {0}; 
    char *p = s; 
    unsigned a[LMAX] = {0}; 
    unsigned long res = 0; 
    unsigned n1s = 0; 
    unsigned n0s = 0; 
    size_t len = 0; 
    size_t i = 1; 
    FILE *fp = NULL; 

    if (!(fp = fopen (argv[1], "r"))) { 
     fprintf (stderr, "error: file open failed.\n"); 
     return 1; 
    } 

    if (!(fgets (s, LMAX - 1, fp))) { 
     fprintf (stderr, "error: failed to read line from file.\n"); 
     return 1; 
    } 
    fclose (fp); 

    /* fill a[i] with number of 1's before i in s */ 
    while (*p && *p != '\n') 
    { 
     a[i] = a[i-1] + *p - '0'; 
     if (*p == '1') n1s += 1; else n0s +=1; 
     p++; i++; 
    } 
    len = p - s; 

    p = s; 
    i = 1; 
    /* for each '0' in s, multiply 1's before i with 1's after i 
    and add product to result (i.e. the # of 101's for that 0) */ 
    while (*p && *p != '\n') 
    { 
     if (*p == '0') 
      res += (unsigned long)a[i - 1] * (a[len] - a[i]); 
     p++; i++; 
    } 

    printf ("\n num 1's : %u\n num 0's : %u\n length : %zu\n results : %lu\n\n", 
      n1s, n0s, len, res); 

    return 0; 
} 

回答

$ ./bin/num101s d434839c-d-input-d4340a6.txt 

num 1's : 434105 
num 0's : 434684 
length : 868789 
results : 13653596984029524 

该解决方案的数据文件可以在这里找到截至解决方案的日期:Input Data

倾倒到汇编程序后,出现如下克提供了一个指令优势在Linux/x86_64的原始比较:

a[i] = a[i-1] + *p - '0'; 

原:由``的scanf使用

a[i] = a[i-1] + (*p == '1'); 
+0

哦。那很有意思。如果有时这样的小细节会影响程序的行为或速度有多快,这很奇怪。感谢分享。 – Chadi 2015-03-28 06:14:01

+0

这是一个很好的问题,并提供了一个很好的挑战和机会,重新审视大部分时间都会被掩盖的大量基本信息。是的,我一直在寻找调整。例如,我一直在使用内联汇编程序来查找迄今为止见过的最快的数字,昨天,我在__fls.h的内核中发现了另一个快了1000%的数字。进行100000000 msb计算的结果是.005秒,而装配例程的结果是0.175秒。 Amazing.Thanks。 – 2015-03-28 15:38:01

+0

谢谢@David。你介意和我们分享这个套路吗? – Chadi 2015-03-29 18:32:29