我如何解决这个问题,使其更有效率?

时间:2015-10-11 09:29:37

标签: c++ algorithm dynamic-programming

所以,我试图解决以下问题:https://www.codechef.com/TSTAM15/problems/ACM14AM3

  
    

火星轨道飞行任务探测器从Satish Dhawan航天中心(Sriharikota Range SHAR)的第一发射台起飞,Andhra     Pradesh,使用极地卫星运载火箭(PSLV)火箭C25     2013年11月5日09:08 UTC(14:38 IST)。

  
     

这次成功发射的秘诀是ISRO的发射台   用过的。发射台的一个重要部分是发射塔。它是   支撑火箭的长垂直结构。

     

ISRO现在想为他们的下一个任务建立一个更好的发射台。   为此,ISRO已经获得了一个长钢筋,并且发射塔可以   通过从栏中切割一段来制作。作为节省成本的一部分,   他们获得的酒吧不是同质的。

     

酒吧由几个街区组成,第i个街区有   耐久性S [i],它是0到9之间的数字   定义为一个或多个块的任何连续组。

     

如果他们从 ith 块中删除了一段栏到第j 块   (i <= j),然后由(S[i]*10(j-i) + S[i+1]*10(j-i-1) + S[i+2]*10(j-i-2) + … + S[j] * 10(0)) % M给出所得片段的耐久性。换句话说,如果W(i,j)是由...形成的基数为10的数字   连接数字S[i]S[i+1]S[i+2],...,S[j],然后   细分(i,j)的持久性为W(i,j) % M

     

由于技术原因,ISRO不会透露,耐用性   用于建造发射塔的部分应该是正确的L.   给定S和M,找出ISRO可以从中删除一个段的方式的数量   耐用性为L的钢筋。输入

     

第一行包含字符串S.此字符串的第i个字符   代表第i段的耐久性。下一行包含一个   单个整数Q,表示查询的数量。每个下一个Q.   行包含两个空格分隔的整数,表示M和L.输出

     

对于每个查询,输出切割条形的方式数量   分开的。约束

1 ≤ |S| ≤ 2 * 10^4
Q ≤ 5
0 < M < 500
0 ≤ L < M
           

实施例

     

<子>的输入

23128765
3
7 2
9 3
15 5
     

<子> 输出

9
4
5
     

<子>的说明

     

对于M=9L=3,除以下的余数为3的子字符串   9是:3,31287,12和876。

现在,我所做的是,我最初生成给定长度的所有可能的数字子串,并尝试将其除以给定的数字,以检查它是否可被整除并将其添加到答案中。因此,我的代码是,

string s;
    cin>>s;
    int m,l,ans=0;
    for ( i = 0; i < s.length(); i++ )
    {
        for ( j = i+1; j < s.length(); j++ )
        {
            string p = s.substr(i,j);
            long long num = stoi(p);
            if (num%m == l)
                ans++;
        }
    }
    cout<<ans<<"\n";
    return 0;

但很明显,由于输入长度高达10 ^ 4,因此无法在所需时间内工作。我怎样才能让它更优化?

2 个答案:

答案 0 :(得分:1)

我可以给你一点建议是将变量初始化为s.length(),以避免每次为for块调用该函数。

答案 1 :(得分:0)

好的,这里有一个工作程序在底部

主要优化#1

在整数运算方面,不要(曾经)使用字符串。您正在转换字符串=&gt;一遍又一遍的整数(这是一个O(n ^ 2)问题),这是一个非常缓慢的问题。此外,它也忽略了这一点。

解决方案:首先将您的字符数组(字符串)转换为数字数组。整数算术 fast

主要优化#2

使用来自&#34; substring&#34;的智能转换数字。将字符转换为实际整数后,它们将成为多项式a_n * 10^n中的因子。要将 n 段的子字符串转换为数字,只需计算sum(a_i * 10^i)的{​​{1}}即可。

很好,如果系数a_i按照它们在问题语句中的方式排列,你可以使用Horner的方法(https://en.wikipedia.org/wiki/Horner%27s_method)来非常快速评估子串的数值。

简而言之:保持当前子字符串的运行值并将其增加一个元素只是0 <= i < n

示例:string&#34; 128472373&#34;。

  • First substring =&#34; 1&#34;,value = 1。
  • 对于我们需要的第二个子字符串 添加数字&#34; 2&#34;如下:* 10 + new element,因此:value = value * 10 + "2"
  • 对于第3个子字符串,需要添加数字&#34; 8&#34;:value = 1 * 10 + 2 = 12,因此:value = value * 10 + "8"
  • 等等。

我在内联格式化C ++代码方面遇到了一些问题,所以我把它放在了IDEone中:https://ideone.com/TbJiqK

该计划的要点:

在主循环中,循环遍历所有可能的起点:

value = 12 * 10 + 8 = 128

// For all startpoints in the segments array ... for(int* f=segments; f<segments+n_segments; f++) // add up the substrings that fullfill the question n += count_segments(f, segments+n_segments, m, l); // Output the answer for this question cout << n << endl; 功能的实施:

count_segments()