Raney引理:
设整数序列A={Ai,i=1,2,...,N},且部分和为Sk=A1+,...,+Ak,序列中的所有的数字之和为Sn=1;
则在A的N个循环表示中,有且仅有一个序列B,满足B的任意部分和Si均大于零。
证明:
由于Sn=1,则Sk+Sn=Sk+1,存在这样一个数x,当在x和x+1之间的某点过后,其后所有的点都在0以上。
用几何图形来说明就是,用两条线夹住Si的曲线,在每连续N个单位的长度中,直线与函数图像有且仅有一个交点。因为斜率为1/N,所以,直线在N个连续长度中,最多只能到达一次整数点。这个交点是在这以后的N个点中,最低的。同时N个单位长度仅有一个交点也证明了该解的唯一性。
关于Raney的另一条引理:任何一种循环表示都和自身不同。如果相同,根据循环串的性质,必定可以分成d>1个相同的部分,设部分和为s,则s*d=1,不能保证s为整数。
有这样一道题目:
序列
一个序列{Ai,i=0,1,2,....,3n},由 3n+1项组成,每一项是1或-2。定义部分和Sk=A0+A1+...+Ak,求所有满足S3n=1,而且对k=0,1,...3n,Sk>0,的序列的个数。
由题意,总共有Cn3n+1种不同的序列,而由于每个序列有3n+1种不同的循环序列,但只有一种的部分和都大于0.所以,总共有Cn3n+1/(3n+1)种满足题目要求的序列。
该问题需要使用到大数乘法和大数除法,程序编码如下
#ifndef SEQ_H #define SEQ_H #include <iostream> #include <memory.h> class Seq { int n; int ans[3001]; int ansLen; public: Seq() { std::cin>>n; memset(ans,0,sizeof(int)*3001); ans[1]=1; ansLen=1; for(int i=1;i<=n;i++) { multiply(3*n+1-i+1); div(i); } div(3*n+1); for(int i=ansLen;i>0;i--) std::cout<<ans[i]; std::cout<<std::endl; } void multiply(int k) { for(int i=1;i<=ansLen;i++) { ans[i]=ans[i]*k; } for(int i=1;i<=ansLen;i++) { while(ans[i]/10>0) { ans[i+1]+=ans[i]/10; ans[i]=ans[i]%10; i++; } if(ansLen<i) ansLen=i; } } void div(int k) { int* b=new int[3001]; memset(b,0,sizeof(int)*3001); int x=0; for(int i=ansLen;i>0;i--) { b[i]=(x*10+ans[i])/k; x=(x*10+ans[i])%k; } b[0]=ansLen; while(b[ansLen]==0&&ansLen>0) ansLen--; memset(ans,0,sizeof(int)*3001); for(int i=1;i<=ansLen;i++) ans[i]=b[i]; delete[] b; } }; #endif