A TempleOS distro for heretics
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

#### 375 lines 6.8 KiB Raw Blame History

 `/*The magic pairs problem:` `Let SumFact(n) be the sum of factors` `of n.` `Find all n1,n2 in a range such that` `SumFact(n1)-n1-1==n2 and` `SumFact(n2)-n2-1==n1` `-----------------------------------------------------` `To find SumFact(k), start with prime factorization:` `k=(p1^n1)(p2^n2) ... (pN^nN)` `THEN,` `SumFact(k)=(1+p1+p1^2...p1^n1)*(1+p2+p2^2...p2^n2)*` `(1+pN+pN^2...pN^nN)` `PROOF:` `Do a couple examples -- it's obvious:` `48=2^4*3` `SumFact(48)=(1+2+4+8+16)*(1+3)=1+2+4+8+16+3+6+12+24+48` `75=3*5^2` `SumFact(75)=(1+3)*(1+5+25) =1+5+25+3+15+75` `Corollary:` `SumFact(k)=SumFact(p1^n1)*SumFact(p2^n2)*...*SumFact(pN^nN)` `*/` `//Primes are needed to sqrt(N). Therefore, we can use U32.` `class PowPrime` `{` ` I64 n;` ` I64 sumfact; //Sumfacts for powers of primes are needed beyond sqrt(N)` `};` `class Prime` `{` ` U32 prime,pow_cnt;` ` PowPrime *pp;` `};` `I64 *PrimesNew(I64 N,I64 *_sqrt_primes,I64 *_cbrt_primes)` `{` ` I64 i,j,sqrt=Ceil(Sqrt(N)),cbrt=Ceil(N`(1/3.0)),sqrt_sqrt=Ceil(Sqrt(sqrt)),` ` sqrt_primes=0,cbrt_primes=0;` ` U8 *s=CAlloc((sqrt+1+7)/8);` ` Prime *primes,*p;` ` for (i=2;i<=sqrt_sqrt;i++) {` ` if (!Bt(s,i)) {` ` j=i*2;` ` while (j<=sqrt) {` ` Bts(s,j);` ` j+=i;` ` }` ` }` ` }` ` for (i=2;i<=sqrt;i++)` ` if (!Bt(s,i)) {` ` sqrt_primes++; //Count primes` ` if (i<=cbrt)` ` cbrt_primes++;` ` }` ` p=primes=CAlloc(sqrt_primes*sizeof(Prime));` ` for (i=2;i<=sqrt;i++)` ` if (!Bt(s,i)) {` ` p->prime=i;` ` p++;` ` }` ` Free(s);` ` *_sqrt_primes=sqrt_primes;` ` *_cbrt_primes=cbrt_primes;` ` return primes;` `}` `PowPrime *PowPrimesNew(I64 N,I64 sqrt_primes,Prime *primes,I64 *_num_powprimes)` `{` ` I64 i,j,k,sf,num_powprimes=0;` ` Prime *p;` ` PowPrime *powprimes,*pp;` ` p=primes;` ` for (i=0;iprime));` ` p++;` ` }` ` p=primes;` ` pp=powprimes=MAlloc(num_powprimes*sizeof(PowPrime));` ` for (i=0;ipp=pp;` ` j=p->prime;` ` k=1;` ` sf=1;` ` while (jn=j;` ` pp->sumfact=sf;` ` j*=p->prime;` ` pp++;` ` p->pow_cnt++;` ` }` ` p++;` ` }` ` *_num_powprimes=num_powprimes;` ` return powprimes;` `}` `I64 SumFact(I64 n,I64 sqrt_primes,Prime *p)` `{` ` I64 i,k,sf=1;` ` PowPrime *pp;` ` if (n<2)` ` return 1;` ` for (i=0;iprime)) {` ` n/=p->prime;` ` k++;` ` }` ` if (k) {` ` pp=p->pp+(k-1);` ` sf*=pp->sumfact;` ` if (n==1)` ` return sf;` ` }` ` p++;` ` }` ` return sf*(1+n); //Prime` `}` `Bool TestSumFact(I64 n,I64 target_sf,I64 sqrt_primes,I64 cbrt_primes,Prime *p)` `{` ` I64 i=0,k,b,x1,x2;` ` PowPrime *pp;` ` F64 disc;` ` if (n<2)` ` return FALSE;` ` while (i++prime)) {` ` n/=p->prime;` ` k++;` ` }` ` if (k) {` ` pp=p->pp+(k-1);` ` if (ModU64(&target_sf,pp->sumfact))` ` return FALSE;` ` if (n==1) {` ` if (target_sf==1)` ` return TRUE;` ` else` ` return FALSE;` ` }` ` }` ` p++;` ` }` `/* At this point we have three possible cases to test` `1)n==p1 ->sf==(1+p1) ?` `2)n==p1*p1 ->sf==(1+p1+p1^2) ?` `3)n==p1*p2 ->sf==(p1+1)*(p2+1) ?` `*/` ` if (1+n==target_sf) {` ` while (i++prime)) {` ` n/=p->prime;` ` k++;` ` }` ` if (k) {` ` pp=p->pp+(k-1);` ` if (ModU64(&target_sf,pp->sumfact))` ` return FALSE;` ` if (n==1) {` ` if (target_sf==1)` ` return TRUE;` ` else` ` return FALSE;` ` }` ` }` ` p++;` ` }` ` if (1+n==target_sf)` ` return TRUE;` ` else` ` return FALSE;` ` }` ` k=Sqrt(n);` ` if (k*k==n) {` ` if (1+k+n==target_sf)` ` return TRUE;` ` else` ` return FALSE;` ` } else {` `// n==p1*p2 -> sf==(p1+1)*(p2+1) ? where p1!=1 && p2!=1` ` // if p1==1 || p2==1, it is FALSE because we checked a single prime above.` ` // sf==(p1+1)*(n/p1+1)` ` // sf==n+p1+n/p1+1` ` // sf*p1==n*p1+p1^2+n+p1` ` // p1^2+(n+1-sf)*p1+n=0` ` // x=(-b+/-sqrt(b^2-4ac))/2a` ` // a=1` ` // x=(-b+/-sqrt(b^2-4c))/2` ` // b=n+1-sf;c=n` ` b=n+1-target_sf;` `// x=(-b+/-sqrt(b^2-4n))/2` ` disc=b*b-4*n;` ` if (disc<0)` ` return FALSE;` ` x1=(-b-Sqrt(disc))/2;` ` if (x1<=1)` ` return FALSE;` ` x2=n/x1;` ` if (x2>1 && x1*x2==n)` ` return TRUE;` ` else` ` return FALSE;` ` }` `}` `U0 PutFactors(I64 n) //For debugging` `{` ` I64 i,k,sqrt=Ceil(Sqrt(n));` ` for (i=2;i<=sqrt;i++) {` ` k=0;` ` while (!(n%i)) {` ` k++;` ` n/=i;` ` }` ` if (k) {` ` "%d",i;` ` if (k>1)` ` "^%d",k;` ` '' CH_SPACE;` ` }` ` }` ` if (n!=1)` ` "%d ",n;` `}` `class RangeJob` `{` ` CDoc *doc;` ` I64 num,lo,hi,N,sqrt_primes,cbrt_primes;` ` Prime *primes;` ` CJob *cmd;` `} rj[mp_cnt];` `I64 TestCoreSubRange(RangeJob *r)` `{` ` I64 i,j,m,n,n2,sf,res=0,range=r->hi-r->lo,` ` *sumfacts=MAlloc(range*sizeof(I64)),` ` *residue =MAlloc(range*sizeof(I64));` ` U16 *pow_cnt =MAlloc(range*sizeof(U16));` ` Prime *p=r->primes;` ` PowPrime *pp;` ` MemSetI64(sumfacts,1,range);` ` for (n=r->lo;nhi;n++)` ` residue[n-r->lo]=n;` ` for (j=0;jsqrt_primes;j++) {` ` MemSet(pow_cnt,0,range*sizeof(U16));` ` m=1;` ` for (i=0;ipow_cnt;i++) {` ` m*=p->prime;` ` n=m-r->lo%m;` ` while (npp[i-1];` ` sumfacts[n]*=pp->sumfact;` ` residue [n]/=pp->n;` ` }` ` p++;` ` }` ` for (n=0;nlo;nhi;n++) {` ` sf=sumfacts[n-r->lo];` ` n2=sf-n-1;` ` if (nN) {` ` if (r->lo<=n2hi && sumfacts[n2-r->lo]-n2-1==n ||` ` TestSumFact(n2,sf,r->sqrt_primes,r->cbrt_primes,r->primes)) {` ` DocPrint(r->doc,"%u:%u\n",n,sf-n-1);` ` res++;` ` }` ` }` ` }` ` Free(pow_cnt);` ` Free(residue);` ` Free(sumfacts);` ` return res;` `}` `#define CORE_SUB_RANGE 0x1000` `I64 TestCoreRange(RangeJob *r)` `{` ` I64 i,n,res=0;` ` RangeJob rj;` ` MemCpy(&rj,r,sizeof(RangeJob));` ` for (i=r->lo;ihi;i+=CORE_SUB_RANGE) {` ` rj.lo=i;` ` rj.hi=i+CORE_SUB_RANGE;` ` if (rj.hi>r->hi)` ` rj.hi=r->hi;` ` res+=TestCoreSubRange(&rj);` ` n=rj.hi-rj.lo;` ` lock {progress1+=n;}` ` Yield;` ` }` ` return res;` `}` `I64 MagicPairs(I64 N)` `{` ` F64 t0=tS;` ` I64 res=0;` ` I64 sqrt_primes,cbrt_primes,num_powprimes,` ` i,k,n=(N-1)/mp_cnt+1;` ` Prime *primes=PrimesNew(N,&sqrt_primes,&cbrt_primes);` ` PowPrime *powprimes=PowPrimesNew(N,sqrt_primes,primes,&num_powprimes);` ` "N:%u SqrtPrimes:%u CbrtPrimes:%u PowersOfPrimes:%u\n",` ` N,sqrt_primes,cbrt_primes,num_powprimes;` ` progress1=0;` ` *progress1_desc=0;` ` progress1_max=N;` ` k=2;` ` for (i=0;iN) k=N;` ` rj[i].hi=k;` ` rj[i].N=N;` ` rj[i].sqrt_primes=sqrt_primes;` ` rj[i].cbrt_primes=cbrt_primes;` ` rj[i].primes=primes;` ` rj[i].cmd=JobQue(&TestCoreRange,&rj[i],mp_cnt-1-i,0);` ` }` ` for (i=0;i