/*
Name: Big int
Copyright: free
Author: No Name
Date: 17/04/16 13:40
Description: Big int
*/
#include <iostream>
#include <iomanip>
#include <string>
#include <windows.h>
#include <conio.h>
#define ull unsigned long long
const ull INT_e18=1000000000000000000,INT_2=2000000000000000000,
INT_4=4000000000000000000,INT_8=8000000000000000000,
F_32=0xffffffff,F_64=0xffffffffffffffff;
#define inlbinto inline bigint operator
//BIG_SIZE must belong to {4,6,8,10,12,14...}
const int BIG_SIZE=2048;
const int BIG_1=BIG_SIZE-1;
const int OUT_SIZE=((((BIG_SIZE*15/14)>>2)+1)<<2);
const int OUT_1=OUT_SIZE-1;
using namespace std;
class bigint {
friend ostream& operator<<(ostream& out, bigint& x);
friend istream& operator>>(istream& in,bigint& x);
private:
public:
bigint () {
;
};
bigint (const bigint& b) {
for(int i=BIG_SIZE; i;) {
num[--i]=b.num[i];
}
}
bigint (const ull& n) {
ull* i=num+BIG_1;
*i=n;
while(i!=num) (*(--i))=0;
}
inline ull &operator [](unsigned pos) {
return num[pos];
}
inline bigint &operator =(const bigint& b_int) {
for(unsigned i=BIG_SIZE; --i;) num[i]=b_int.num[i];
num[0]=b_int.num[0];
return *this;
}
inline bigint &operator =(const ull &_ull_int) {
ull* i=num+BIG_1;
*i=_ull_int;
while(i!=num) (*(--i))=0;
return *this;
}
inline bigint &operator =(const string str) {
*this=0;
unsigned end=str.size();
for(unsigned i=0; i!=end; ++i) {
(*this).mult_ul(10);
(*this)+=((unsigned long long)(str[i]-48));
}
return *this;
}
inline bigint &operator <<=(unsigned step) {
if(step>=64) {
l_move64(step>>6);
step&=63;
}
unsigned _st_=64-step;
ull a=0,b=0;
for(ull* i=num+BIG_SIZE; i!=num;) {
a=(*(--i)>>_st_);
*i<<=step;
*i|=b;
b=((*--i)>>_st_);
*i<<=step;
*i|=a;
}
return *this;
}
inline bigint &operator >>=(unsigned step) {
if(step>=64) {
r_move64(step>>6);
step&=63;
}
unsigned _st_=64-step;
ull a=0,b=0;
for(int i=-1; i!=BIG_1;) {
a=(num[++i]<<_st_);
num[i]>>=step;
num[i]|=b;
b=(num[++i]<<_st_);
num[i]>>=step;
num[i]|=a;
}
return *this;
}
inlbinto <<(unsigned step) {
bigint b=*this;
b<<=step;
return b;
}
inlbinto >>(unsigned step) {
bigint b=*this;
b>>=step;
return b;
}
inline bigint &operator &=(const bigint &b) {
for(unsigned i=BIG_SIZE; i;) num[--i]&=b.num[i];
return *this;
}
inline bigint &operator |=(const bigint &b) {
for(unsigned i=BIG_SIZE; i;) num[--i]|=b.num[i];
return *this;
}
inline bigint &operator ^=(const bigint &b) {
for(unsigned i=BIG_SIZE; i;) num[--i]^=b.num[i];
return *this;
}
inlbinto &(const bigint &b) {
bigint a=*this;
a&=b;
return a;
}
inlbinto |(const bigint &b) {
bigint a=*this;
a|=b;
return a;
}
inlbinto ^(const bigint &b) {
bigint a=*this;
a^=b;
return a;
}
inline bigint &operator +=(const bigint& b_int) {
for(unsigned i=BIG_SIZE; i;) {
num[--i]+=b_int.num[i];
if(num[i]<b_int.num[i]) while(!++num[--i]);
}
return *this;
}
inline bigint &operator +=(const ull &_ullint) {
if((num[BIG_1]+=_ullint)<_ullint) {
for(unsigned i=BIG_1; !++num[--i];);
}
return *this;
}
inlbinto +(const bigint &b_int) {
bigint r=*this;
r+=b_int;
return r;
}
inlbinto +(const ull &_ullint) {
bigint r=*this;
r+=_ullint;
return r;
}
inline bigint &operator ++() {
for(ull* i=num+BIG_SIZE; !++(*(--i)););
return *this;
}
inline bigint operator ++(int) {
bigint old=*this;
for(ull* i=old.num+BIG_SIZE; !++(*(--i)););
return old;
}
inline bigint &operator -=(const bigint &b_int) {
unsigned j;
for(unsigned i=BIG_SIZE; i;) {
if(num[--i]<(num[i]-=b_int.num[i])) while(~--num[--i]);
}
return *this;
}
inline bigint &operator -=(const ull _ullint) {
if(num[BIG_1]<num[BIG_1]-_ullint) for(unsigned i=BIG_1; ~--num[--i];);
return *this;
}
inlbinto -(const bigint &b_int) {
bigint r=*this;
r-=b_int;
return r;
}
inlbinto -(const ull _ullint) {
bigint r=*this;
r-=_ullint;
return r;
}
inline bigint &operator --() {
for(unsigned i=BIG_SIZE; ~--num[--i];);
return *this;
}
inline bigint operator --(int) {
bigint old=*this;
for(unsigned i=BIG_SIZE; ~--num[--i];);
return old;
}
inline bigint &operator *=(const ull& that) {
if(that>F_32) {
bigint c;
c=*this;
(*this).mult_ul(that>>32);
*this<<=32;
c.mult_ul(that&0xffffffff);
*this+=c;
return *this;
} else mult_ul(that);
}
inlbinto * (ull that) {
bigint b=*this;
return b*=that;
}
inline bigint divi_ul(const ull ula) {
ull b,c=0,d=0;/*
从高位到低位,与上次未除残留c一同取余b, 除, 加已除残留d
对b进行"%""/ "
*/
for(unsigned i=0; i!=BIG_SIZE; ++i) {
b=(num[i]%ula+c%ula);
num[i]=(num[i]/ula+c/ula);
if(b>=ula) {
++num[i];
b-=ula;
}
if((num[i]+=d)<d) ++(num[i-1]);
b<<=32;
c=(b%ula);
c<<=32;
d=(b/ula);
d<<=32;
}
return *this;
}
// BELOW METHODS ARE DEVELOPING!!! DEVELOPING!!! DEVELOPING!!!
inlbinto / (bigint b);
inline bigint &operator /= (bigint b) {
unsigned i=0;
bigint c;
c=*this;
*this=0;
while(i!=BIG_SIZE) {
if(b[i]) break;
++i;
}
b.l_move64(i);
i<<=6;
if(!b[0]&0xffffffff00000000) i+=32;
if(!b[0]&0xffff000000000000) i+=16;
if(!b[0]&0xff00000000000000) i+=8;
if(!b[0]&0xf000000000000000) i+=4;
if(!b[0]&0x3000000000000000) i+=2;
if(!b[0]&0x8000000000000000) ++i;
b<<=(i&63);
++i;
while(--i) {
*this<<=1;
if(b<c) {
c-=b;
num[BIG_1]|=1;
}
b>>=1;
}
if(b<c) num[BIG_1]|=1;
return *this;
}
inlbinto / (ull b);
inline bigint &operator /= (ull b) {
*this-=(*this%b);
unsigned i;
if(!(b&0xffffffff)) b>>=32;
i+=32;
if(!(b&0xffff)) b>>=16;
i+=16;
if(!(b&0xff)) b>>=8;
i+=8;
if(!(b&15)) b>>=4;
i+=4;
if(!(b&3)) b>>=2;
i+=2;
if(!(b&1)) b>>=1;
++i;
*this>>=i;
}
inlbinto % (bigint b);
inline bigint &operator %= (bigint b) {
unsigned i=0;
while(i!=BIG_SIZE) {
if(b[i]) break;
++i;
}
b.l_move64(i);
i<<=6;
if(!b[0]&0xffffffff00000000) i+=32;
if(!b[0]&0xffff000000000000) i+=16;
if(!b[0]&0xff00000000000000) i+=8;
if(!b[0]&0xf000000000000000) i+=4;
if(!b[0]&0x3000000000000000) i+=2;
if(!b[0]&0x8000000000000000) ++i;
b<<=(i&63);
++i;
cout<<b;
while(--i) {
if(b<*this) {
*this-=b;
cout<<"as";
}
b>>=1;
}
if(b<*this) *this-=b;
return *this;
}
inline bigint &operator %= (const ull& that) {
for(unsigned i=31; --i;) {
num[0]%=that;
*this<<=32;
}
num[0]%=that;
return *this;
}
inlbinto % (ull that) {
bigint a=*this;
a%=that;
return a;
}
inlbinto *=(const bigint &b);
inlbinto *(const bigint &b);
//OK???
inline bool operator <(bigint b) {
for(unsigned i=0; i!=BIG_SIZE; ++i) {
if(num[i]<b.num[i]) return true;
else if(num[i]==b.num[i]) continue;
else return false;
}
return false;
}
inline bool operator >(bigint b) {
return b<*this;
}
inline bool operator ==(bigint b) {
for(unsigned i=BIG_SIZE; i;) {
if(num[--i]!=b.num[i]) return false;
}
return true;
}
inline bool operator !=(bigint b) {
for(unsigned i=BIG_SIZE; i;) {
if(num[--i]!=b.num[i]) return true;
}
return false;
}
//private:
ull num[BIG_SIZE];
inline bigint &l_move64(unsigned step) {
unsigned _st_=BIG_SIZE-step,i=0;
for(; i!=_st_; ++i) {
num[i]=num[i+step];
}
while(i!=BIG_SIZE) {
num[i]=0;
++i;
}
}
inline bigint &mult_ul(const unsigned long that) {
ull a=0,b=0,c=0;
for(ull *i=num+BIG_SIZE; i!=num;) {
(a=((*--i)>>32))*=that;
((*i)&=F_32)*=that;
b=(a>>32);
a<<=32;
if(((*i+=c)+=a)<a) ++b;
(a=((*--i)>>32))*=that;
((*i)&=F_32)*=that;
c=(a>>32);
a<<=32;
if(((*i+=b)+=a)<a) ++c;
}
return *this;
}
inline bigint &r_move64(unsigned step) {
unsigned _st_=BIG_SIZE-step,i=BIG_SIZE;
for(; i!=step; i) {
num[--i]=num[i-step];
}
while(i) {
num[--i]=0;
}
}
};
ostream& operator<<(ostream& out,bigint& x) {
ull outint[OUT_SIZE]= {};
int t;
ull cx,h1,h2,*n,*i=x.num,*end=i+BIG_SIZE,*endo=outint+OUT_SIZE;
while((!(*i))&&i<end) ++i;
for(; i!=end; ++i) {
cx=*i;
for(t=17; --t;) {
h2=0;
for(n=endo; n!=outint;) {
*(--n)<<=4;
h1=0;
if(*n>=INT_8) {
h1|=8;
(*n)-=INT_8;
}
if(*n>=INT_4) {
h1|=4;
(*n)-=INT_4;
}
if(*n>=INT_2) {
h1|=2;
(*n)-=INT_2;
}
if(*n>=INT_e18) {
h1|=1;
(*n)-=INT_e18;
}
(*n)|=h2;
*(--n)<<=4;
h2=0;
if(*n>=INT_8) {
h2|=8;
*n-=INT_8;
}
if(*n>=INT_4) {
h2|=4;
*n-=INT_4;
}
if(*n>=INT_2) {
h2|=2;
*n-=INT_2;
}
if(*n>=INT_e18) {
h2|=1;
*n-=INT_e18;
}
(*n)|=h1;
}
*(endo-1)|=(cx>>60);
cx<<=4;
}
}
for(n=outint; (n!=endo)&&(!(*n)); ++n);
if(n==endo) --n;
out<<(*n);
while(++n!=endo) {
out<<setfill('0')<<setw(18)<<*n;
}
return out;
}
istream& operator>>(istream& in,bigint &x) {
char str[OUT_SIZE]= {};
in>>str;
unsigned end;
for(end=0; str[end]!=0; ++end);
x=0;
for(unsigned i=0; i!=end; ++i) {
x*=10;
x+=(str[i]-48);
}
return in;
}
bigint mult(const bigint &a,const unsigned long &b) {
bigint r;
r=a;
r.mult_ul(b);
return r;
}
unsigned long mod(const bigint &a,const ull &b) {
ull r=0;
for(unsigned i=0; i!=BIG_1; ++i) {
r+=(a.num[i]%b);
r%=b;
r<<=32;
r%=b;
r<<=32;
r%=b;
}
r+=(a.num[BIG_1]%b);
r%=b;
return (unsigned long) r;
}
bigint divi(const bigint &a,const unsigned long &b) {
bigint r;
r=a;
return r.divi_ul(b);
}
bigint fact(ull n) {
bigint r=1;
ull i=1,a;
if(n%2) {
r=n;
--n;
}
while(n>i) {
a=n*i;
r*=a;
--n;
++i;
}
return r;
}
bigint nCr(ull x,ull y) {
if(x-y>y) y=x-y;
ull a=x-y;
++x;
bigint b=1;
if(a&1) b=--x;
if(a&2) b*=((--x)*(--x));
while(--x>y) {
b*=((x)*(--x));
b*=((--x)*(--x));
}
if(a&1) {
b.divi_ul(a);
--a;
}
while(a) {
(x=a)*=(--a);
b.divi_ul(x);
--a;
}
return b;
}
int main() {
bigint a;
ull x,y,c;
while(true) {
cin>>x>>y;
c=GetTickCount();
a=nCr(x,y);
cout<<"fact time: "<<(GetTickCount()-c)<<endl;
c=GetTickCount();
cout<<a<<endl;
cout<<"output time: "<<(GetTickCount()-c)<<endl;
}
}
#undef ull
#undef inlbinto