简体   繁体   中英

Summation of a number made up of 4 5 6

We are given three integers x, y and z. You have to find the sum of all numbers whose digits are made of only 4, 5 and 6, that have at most x fours in decimal representation, at most y fives in decimal representation and at most z sixes in decimal representation

I am using the concept Describe Here

My code:

// fact[i] is i!
    for(int i=0;i<=x;i++)
        for(int j=0;j<=y;j++)
            for(int k=0;k<=z;k++){

           int t = i+j+k;
           if(t==0) continue;
           long ways = fact[t-1];
           long pow = (long) Math.pow(10,t-1);
           long rep=0;
           if(i!=0){
               rep = fact[j]*fact[k];
               if(i>0) rep*=fact[i-1];

              o+= 4*pow*(ways/rep); 
           }

           if(j!=0){
               rep = fact[i]*fact[k];
               if(j>0) rep*=fact[j-1];

              o+= 5*pow*(ways/rep); 
           }

           if(k!=0){
               rep = fact[i]*fact[j];
               if(k>0) rep*=fact[k-1];

              o+= 6*pow*(ways/rep); 
           }

        }

But I am getting the wrong answer for x=1 , y=1 and z=1 i am getting 3315 while the correct answer is 3675 .

Please help me find my mistake.

4+5+6+45+54+56+65+46+64+456+465+546+564+645+654=3675

The problem is not with your code, it's with your logic: Let S be the set of numbers consisting of only the digits 4, 5 and 6. You want to compute SUM(S). But since you're only considering the first digits of those numbers, you're in fact computing SUM(s in S, s - s % 10^floor(log10(s))).

You're doing that correctly though, because

4 + 5 + 6 + 40 + 50 + 50 + 60 + 40 + 60 + 400 + 400 
  + 500 + 500 + 600 + 600 = 3315

Long story short, all you need to do is apply user גלעד ברקן's approach below to fix your code. It will result in an O(xyz(x+y+z)) algorithm and can be improved to O(xyz) by seeing that SUM(i = 0 to t-1, 10^i) = (10^t - 1) / 9, so it's really enough to change a single line in your code:

// was: long pow = (long) Math.pow(10,t-1);
long pow = (long) (Math.pow(10,t)-1) / 9;

There is also a really simple O(xyz) time + space approach using dynamic programming that uses only a minimum of math and combinatrics: Let g(x, y, z) be tuple (count, sum) where count is the number of 4-5-6-numbers comprised of at exactly x fours, y fives and z sixes. sum is their sum. Then we have the following recurrence:

using ll=long long;
pair<ll, ll> g(int x, int y, int z) {
    if (min(x,min(y,z)) < 0)
        return {0,0};
    if (max(x,max(y,z)) == 0)
        return {1,0};
    pair<ll, ll> result(0, 0);
    for (int d: { 4, 5, 6 }) {
        auto rest = g(x - (d==4), y - (d==5), z - (d==6));
        result.first += rest.first;
        result.second += 10*rest.second + rest.first*d;
    }
    return result;
}

int main() {
    ll res = 0;
    // sum up the results for all tuples (i,j,k) with i <= x, j <= y, k <= z
    for (int i = 0; i <= x; ++i)
        for (int j = 0; j <= y; ++j)
            for (int k = 0; k <= z; ++k)
                res += g(i, j, k).second;
    cout << res << endl;
}

We can add memoization to g to avoid computing results twice, yielding a polynomial time algorithm without needing combinatoric insights.

This is easy to generalize for the case where you have more than 3 digits you can use, as demonstrated by gen-ys's answer . It is also generalizable to cases where you have more complex restrictions on the shape of your numbers. It can even be generalized if you want to sum the numbers in a given range, by combining it with another generic DP approach .

EDIT: There's also a way to describe your function f(x, y, z) directly, the sum of 4-5-6-numbers containing at most x fours, y fives and z sixes. You need inclusion-exclusion for that. For example, for the counting part we have

c(x, y, z) = c(x-1,y,z) + c(x,y-1,z) + c(x,y,z-1) - c(x-1,y-1,z) - c(x-1,y,z-1) - c(x,y-1,z-1) + c(x-1,y-1,z-1)

It's slightly more complicated for the sums.

in Python 3:

def sumcalc(x,y,z):
  if x < 0 or y < 0 or z < 0: return -1
  import itertools
  sum = 0
  for i, j, k in itertools.product(range(x + 1), range(y + 1), range(z + 1)):
    e = (('4' * i) + ('5' * j) + ('6' * k))
    if e:
      perms = [''.join(p) for p in itertools.permutations(e)]  
      for i in set(perms): sum += int(i)
  return sum

This method is straightforward and can be used with most any programming language not necessarily including similar syntactic sugar if any. The basic steps are:

  1. For given integers x, y and z all >= 0, write one string for each of all combinations disregarding order of '4' from 0 to x occurrences with '5' from 0 to y occcurrences and with '6' from 0 to z occurrences. (However the combinations are generated in an order to ensure completeness.)

  2. For each string produced in (1) generate all unique and non-empty permutations of its characters.

  3. For each string permutation produced in (2) convert it to an integer and add it to the sum.

Python 3 integers have unlimited precision so its not necessary to drag in a Long or BigInteger type to improve it.

Your logic is almost correct. You just forgot that each digit can appear in each position ( pow in your terms) for each configuration of (i,j,k) . You can fix your code easily by adding an additional loop:

for(int i=0;i<=x;i++)
  for(int j=0;j<=y;j++)
    for(int k=0;k<=z;k++){

       int t = i+j+k;

       for (int p=0; p<t; p++){               // added loop
         long ways = fact[t-1];
         long pow = (long) Math.pow(10,p);   // changed

Or, even better, thanks to Niklas B.'s comment: instead of adding a loop just assign pow to

pow = (long) Math.pow(10,t - 1) / 9

EDIT: I realized that the post linked describes something identical. I mistook it to be linked to a similar problem floating on SO a few days ago which was solved completely differently. Hence deleted it but later undeleted as it could explain the errors in code to the OP.

This can be solved as a combinatorial problem with a complexity of O(x y z) .

Let us split the problem into two parts:

Part-A: Find the sums of numbers comprising of exactly x 4s, y 5s and z 6s. This is fairly simple:

  1. Let the number be as follows: _ _ _..._ 4 _ ... _ , where the 4 shown appears in the 10^k position. The rest of the numbers can be arranged in (x+y+z-1)! / ((x-1)! * y! * z!) (x+y+z-1)! / ((x-1)! * y! * z!) ways. Hence the total sum contributed by 4 in this position is 4 * 10^k * (x+y+z-1)! / ((x-1)! * y! * z!) 4 * 10^k * (x+y+z-1)! / ((x-1)! * y! * z!) which is 4 * x * 10^k * (x+y+z-1)! / (x! * y! * z!) 4 * x * 10^k * (x+y+z-1)! / (x! * y! * z!) .

  2. Likewise 5 and 6 contribute and the total contribution from digits in this position is: 10^k * (x+y+z-1)! / (x! * y! * z!) * (4x + 5y + 6z) 10^k * (x+y+z-1)! / (x! * y! * z!) * (4x + 5y + 6z) .

(For example, with x=y=z=1 and at the 10^2 position, the contribution is 400*2 + 500*2 + 600*2 = 3000 (as per the example). As per the calculation it is 100 * 2! / (1! * 1! * 1!) * (4+5+6) = 3000 .)

  1. Hence the overall contribution of (x+y+z) digit numbers is:

(x+y+z-1)! / (x! * y! * z!) * (4x + 5y + 6z) * (10^0 + 10^1 + ... + 10^(x+y+z-1))

= (x+y+z-1)! / (x! * y! * z!) * (4x + 5y + 6z) * (10^(x+y+z) - 1) / 9

So in the above example the sum of all 3-digit numbers should be: 2! / (1! * 1! * 1!) * (4+5+6) * (999)/9 = 3330 2! / (1! * 1! * 1!) * (4+5+6) * (999)/9 = 3330 . As per the example it is: 456+465+546+564+645+654 = 3330 .

Part-B:

  1. Do the same as above but with xy and z taking on values from 0-x, 0-y and 0-z respectively. This can be done by a 3-way nested loop in (0..x), (0..y), (0..z) end-points inclusive. In each iteration use the above formula

  2. So for the example above we have x:0-1, y:0-1, z:0-1. The possible indices are {(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)} . The sums as per the above formula for 2-digit numbers are, for example:

    (0, 1, 1): 1!/(0! * 1! * 1!) * (5+6) * 99/9 = 121 (1, 0, 1): 1!/(1! * 0! * 1!) * (4+6) * 99/9 = 110 (1, 1, 0): 1!/(1! * 1! * 0!) * (4+5) * 99/9 = 99

which add up to 330 . In the example, 45+54+56+65+46+64 = 330 .

Likewise for the units which gives 15. Hence the total sum is 15+330+3330=3675 .

Note:

  1. The above can be generalized to the linked problem and any number of digits (doesn't require the numbers to be consecutive). If you have zeroes in the digits, the method has to be slightly tweaked but the fundamentals are the same.

  2. You could use similar techniques to figure out the number of 7's occurring from 1 to 1 million etc. It's a powerful combinatorial method.

Solution in python 3 which uses permutation with duplicates algorithm. Can be adapted to other cases as the input is a dictionary that has keys as the requested digits, and values are the counts of each digit.

Explanation of the algorithm: You can look at the permutations as a tree, where the root contains a zero-length number, its children represent 1-digit numbers, the next level has 2-digit numbers etc. Each node has 3 children, which represent the parent node's value extended by a digit. So the algorithm is basically a pre-order tree walk. Each recursive call gets the current number, and the digits left to add (maintained in a dictionary with the digits as keys, and the counts as values). It iterates on the dictionary adding each of the possible digits in turn, and then recurses with the new number and the digits left. The method also returns the current number in the beginning, and then performs said recursion.

#!/usr/bin/env python3

import itertools
import copy

class Matrix:
  def __init__(self, dim):
    m=None
    for i in dim:
      m=[copy.deepcopy(m) for j in range(i)]
    self.mat=m
  def getVal(self, coord):
    m=self.mat
    for i in coord:
      m=m[i]
    return m
  def setVal(self, coord, val):
    m=self.mat
    l=coord.pop()
    for i in coord:
      m=m[i]
    coord.append(l)
    m[l]=val

def sumOfNumbers(digits):
  def _sumOfNumbers(counts):
    max_v=-1
    for v in counts:
      if v<0:
        return (0,0)
      elif v>max_v:
        max_v=v
    if m.getVal(counts)==None:
      c=0
      s=0
      if max_v==0:
        c=1
      else:
        for i, d in enumerate(digits.keys()):
          counts[i]-=1
          r=_sumOfNumbers(counts)
          counts[i]+=1
          c+=r[0]
          s+=r[1]*10+r[0]*d

      m.setVal(counts, (c,s))
    return m.getVal(counts)

  dim=[v+1 for v in digits.values()]
  m=Matrix(dim)
  tot_val=0
  for i in itertools.product(*map(lambda x: range(x), dim)):
    r=_sumOfNumbers(list(i))
    tot_val+=r[1]

  return tot_val

def main():
  x=1
  y=1
  z=1
  print(x,y,z)
  print(sumOfNumbers({4: x, 5: y, 6: z}))

if __name__ == "__main__":
  main()

here's what you need!! hope it works correctly:)

using namespace std;

typedef long long ll;

const ll mod = 1000000007;

int main() {

int  q, a=0, b=0, c=0, x, y, z,  l, r,count=0;
long long int  sum = 0,i,n,temp;
cin >> x >> y>>z;
string xyz = "4";
for (i = 0; i>-1; i++)
{
    n = i;
    //sum = 12345620223994828225;
    //cout << sum;
    while (n > 0)
    {
        temp = n % 10;
        if
            (temp == 4)
        {
            a++;
        }
        if (temp == 5)
        {
            b++;
        }
        if (temp == 6)
        {
            c++;
        }
        count++;
        n = n / 10;

    }

    if (a <= x && b <= y && c <= z && (a + b + c) == count)
    {
        temp = i%mod;
        sum = (sum + temp) % mod;

    }
    else if ((a + b + c) > (x + y + z))
        break;
    if (count == c)
    {
        i = 4 * pow(10, c);
    }
    count = 0;
    a = 0;
    b = 0;
    c = 0;
    temp = 0;
}
cout << sum+4;

return 0;

}

Just count the no of occurances of 4,5 and 6 and store that in the second variable using memoization.. C++ code below

#include <bits/stdc++.h>
#define ll int
#define mod 1000000007
using namespace std;
struct p
{
    ll f,s;
}dp[102][102][102]={0};

p c(ll x,ll y,ll z)
{
    if (min(x,min(y,z)) < 0)
    {
        p temp;
        temp.f=temp.s=0;
        return temp;
    }
    if (!max(x,max(y,z)))
    {
        p temp;
        temp.f=1;
        temp.s=0;
        return temp;
    }
    if(dp[x][y][z].f&&dp[x][y][z].s) return dp[x][y][z];
    p ans;
    ans.f=ans.s=0;
    for (int i=4;i<7;i++)
    {
        p temp;
        if(i==4) temp=c(x-1, y, z);
        if(i==5) temp=c(x, y-1, z);
        if(i==6) temp=c(x, y, z-1);
        ans.f = (ans.f+temp.f)%mod;
        ans.s = ((long long)ans.s+((long long)i)*(long long)(temp.f) + 10*(long long)temp.s)%mod;
    }
    dp[x][y][z].f=ans.f;
    dp[x][y][z].s=ans.s;
  return ans;
}

int main()
{
    ll x,y,z,ans=0;
    scanf("%d%d%d",&x,&y,&z);
    for (ll i = 0; i <= x; ++i)
    {
        for (ll j = 0; j <= y; ++j)
        {
            for (ll k = 0; k <= z; ++k)
            {
               ans = (ans + c(i, j, k).s)%mod;
               cout<<dp[i][j][k].f<<" "<<dp[i][j][k].s<<endl;
            }
        }
    }
    printf("%d",ans);
  return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM