Cod sursa(job #381525)

Utilizator mgntMarius B mgnt Data 10 ianuarie 2010 20:45:39
Problema Cifre Scor 40
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.79 kb
#include <iostream>
#include <fstream>
using namespace std;

// Given A,B,C,K.
// 0<=A<=B<=1 * 1000 * 1000 * 1000
// 0<=C,K<=9
//
// Count how many numbers in [A..B]
// have at least K digits C, return
// count/(B-A+1) with 4 decimals
// after dot.

typedef long long int bnum;

// Returns greatest power of b
// less or equal t.
// PRE: 0<n
bnum
lowerb(int t, int b)
{
  bnum p=1, q;
  while ( ((q=b*p)<=t) ) { p=q; }
  return p;
}

bnum
hexuprec(bnum n)
{
  if ( 0xa > n ) { return 1+n; }
  bnum x=hexuprec(n/0xa),
      y=1+(n%0xa), z=y+(0x10*x);
  return z;
}

bnum
hexup(bnum n)
{
  if ( 0 == n ) { return 1; }
  return hexuprec(n);
}

bnum
hexdnrec(bnum n)
{
  if ( 0x10 > n ) { return n-1; }
  bnum x=hexdnrec(n/0x10),
       y=(n%0x10)-1, z=y+(0xa*x);
  return z;
}

bnum
hexdn(bnum n)
{
  if ( 1 == n ) { return 0; }
  return hexdnrec(n);
}

bnum
aaaa(bnum z)
{
  int p=0xa,q;
  while ( (q=0x10*p+0xa)<z ) { p=q; }
  return p;
}

// Returns how many n in {0<=n<=hexdn(t)}
// have at least s digits c-1 in decimal
// representation.
// prec: t=hexup(tt) for some tt,
// prec: 1<=c<=0xa
// 1==f <--> first digit can be cut to 1
bnum
atleasth(int f, int c, bnum t, int s)
{
  // Set {0<=n<t} is empty.
  if ( 0 >t ) { return 0; }

  // Each in {0<=n<=t} has at least 0 digits c.
  if ( 0==s ) { return 1+hexdn(t); }

  // t is representable by a single digit.
  if ( t<0x10 ) {
    return ((c<=t)&&(1==s))?(1):(0);
  }

  // Cut first digit, deal with rest.
  if ( 1 != c ) { f=1; } // match digit is not 1

  bnum z=lowerb(t,0x10), w=0, r=t%z, d=t/z,i,
      zz= aaaa(z),
      x = atleasth(1,c,zz,s),
      y = atleasth(1,c,zz,s-f),
      x1, y1;
  if ( 1==f ) { x1 = x; y1 = y; } else 
              { y1 = x1 = atleasth(0,c,zz,s); }

  w += ((1==c)?(y1):(x1)); // fist digit is 1
  for ( i=2; d>i; ++i ) {
    w += ((c==i)?(y):(x)); // fist digit is i
  }
  // First digit in t of level 0 of recurrence
  // is 2 at least, so (c==d)?(1):(0) is ok to use.
  w += atleasth(1,c,r,s - ((c==d)?(1):(0))); // rest

  return w; // count
}

// Returns how many n in {0<=n<=t}
// have at least s digits C in decimal
// representation.
// prec: 0<=s, 0<=c<10
// !!! c may be 0
bnum
atleastd(int c, int t, int s)
{
  bnum x = hexup(t);
  return atleasth(0,1+c,x,s);
}

// Print n with width w.
// PRE: 0<w
// PRE: 0<=n<10**w
void
pw (ostream & os, bnum n, int w)
{
  if ( 0==n ) {
    while ( 0<w ) {
      os << '0';
      --w;
    }
    return;
  }

  pw(os, n/10, w-1);
  os << "0123456789"[n%10];
}

int
main ( )
{
  ifstream is("cifre.in");
  ofstream os("cifre.out");
  int A,B,C,K;
  is >> A >> B >> C >> K;
  bnum count = atleastd(C,B,K)-atleastd(C,A-1,K);
  double ans= ((double)count)/(B-A+1);
  // output ans with 4 digit precision ... and accuracy
  int dig4 = (int)(ans*10000);
  os << "0.";
  pw (os, dig4, 4);
  os << endl;
  return 0;
}