我們可以找到兩個長度為n的數列,使得從兩個數列中各自挑選乙個數相交得出的n^2個數正好是1到n^2之間的所有整數。
對於正樣的數列,如果我們將其中乙個數列中所有數都加上乙個常數,另外乙個數列中所有數都減去乙個常數,那麼必然也得到乙個符合條件的數列,所以我們可以認為這樣得到的數列對和原先的數列對 是等價的,不在我們考慮範圍之內。
問題是,相互不等價的數列對有多少個?
而最終的計算程式由於使用大整數,將用到gmp庫。
最終結果挺有意思,同n的因子分解結果有關係。比如
n=p1^a1 *p2^a2*..*pt^at
那麼結果僅僅同a1,a2,...,at有關係,而同p1,p2,...,pt沒有關係。
對於整數n,對於乙個序列
n0=n, n1, n2,...,nk
其中n(i+1)|n(i)而且n(i+1)>n(i), nk=1
我們稱這個序列為n乙個長度為k的因子序列.
比如n長度為1的因子序列只有乙個為n,1.
記n長度為s的因子序列的數目為l(n,s)
那麼l(n,0)=0,l(n,1)=1
上面計數問題的結果即
f(n)=sum
比如對於n=6=2*3
長度為1的因子序列1個
2 2個 ,
長度大於3的因子序列沒有
所以f(6)=1*(1+0)+2*(2+1)=7
而對於n=p^k, 長度為t的因子序列相當於從p,p^2,...,p^(k-1)中選擇t-1個數,共有c(k-1,t-1)個
所以l(p^k, t)=c(k-1,t-1)
f(p^k)=sum
=sum
=sum
=sum
=c(2k-1,k) (從2k-1個樣品中取k個的方案正好是從前k-1個中取s個,後k個中取k-s個,對所有可能的s進行求和)
=(2k-1)!/(k!*(k-1)!),即gxqcn的結論.
我現在寫的程式就是對給定的n,先求出所有的l(n,s),然後計算出f(n).
還沒有找到更加好的辦法.
其實這個方法不僅僅對於n*n的方陣可用,對於將0,1,...,m*n-1填入乙個m*n的矩陣的計數方案也可用.
其中l(n,s)也可以想象成下面的模型
假設
n=p1^r1*p2^r2*...*pt^rt
我們想象有乙個袋子中總共裝了r1+r2+...+rt個球,這些球總共有t種顏色,r1個為第一種顏色,r2個為第二種顏色,...,rt個為第t種顏色.
現在要分s次將袋子種的球取光,請問有多少種方案?
這個方案數就是l(n,s).
找到一種時間複雜度為o(l^2)次乘法的演算法.
其中l=r1+r2+...+rt
定義c(m,n)=m!/(n!*(m-n)!)是組合數.
i)計算組合數c(m,n),其中m=1,2,...,l+max(r)-1. 0<=n<=m (max(r)=max(r1,r2,...,rt))
計算方法
c(1,0)=c(1,1)=1
for(m=2;m發現s(n,m)其實就是c(n+m-1,m-1),所以只要事先計算好組合數就夠了
#include
#include
#include
#include
int *factor_list;
int factor_count;
int l, lar;
mpz_t *********;
mpz_t *f;
mpz_t n;
#define ********(x,y) ********[(x)*lar+(y)]
void set_********()
} } void calc_f()
for(i=0;impz_set(f[k],m);
printf("l[%d]=",k);
mpz_out_str(stdout,10,f[k]);
printf("/n");
} mpz_clear(r);
mpz_clear(m);
} void output_result()
printf("the result is:/n");
mpz_out_str(stdout,10,m);
printf("/n");
mpz_clear(r);
mpz_clear(m);
} #define prime_limit 1048576
#define sqr_limit 1024
int prime_flag[prime_limit];
int *prime_list;
int prime_count;
void init_prime()
} for(i=2,count=0;iprime_count=count;
prime_list=(int *)malloc(sizeof(int)*count);
for(i=2,count=0;i} }
void defactor()
while(!mpz_mod_ui(r,m,prime_list[i]));
if(!mpz_cmp_si(m,1))break;
} }
if(mpz_cmp_si(m,1))
}else
} factor_list=(int *)malloc(sizeof(int)*pc);
factor_count=pc;l=0,maxr=0;
mpz_set(m,n);
for(i=0,pc=0;il+=factor_list[pc];
if(maxrpc++;
if(!mpz_cmp_si(m,1))break;
} }
if(mpz_cmp_si(m,1))
lar=l+maxr+1;
mpz_clear(r);
mpz_clear(m);
} int
main(void)
棧 在乙個長度為n的陣列中實現兩個棧(C )
77.6 c 在乙個長度為n的陣列中實現兩個棧 且共享儲存區 0,max size 1 構棧方法 棧頂相向,迎面增長 include using namespace std 混合順序棧的類arrstack template class arrstack 建構函式 template arrstack ...
求從1到n這n個整數的十進位制表示中1出現的次數
原文連線 題目 輸入乙個整數n,求從1到n這n個整數的十進位制表示中1出現的次數。例如輸入12,從1到12這些整數中包含1 的數字有1,10,11和12,1一共出現了5次。分析 這是一道廣為流傳的google面試題。簡單的方法就是按照給位進行分析 在個位出現1的個數 n 10 個位 0,0 個位 1...
從1到n這n個整數的十進位制表示中1出現的次數
今天遇到乙個題目,求1到n個整數中1出現的次數,這是以前寫過的題目 include include int main printf 含有1的個數為 d n sum return 0 現又從新寫了乙個,並附上思路 include int main printf 含有1的個數為 d n sum retu...