將1到N 2表示成兩個長度為N的數列的正交和

2021-04-12 23:21:53 字數 3314 閱讀 2993

我們可以找到兩個長度為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...