題目連結:http://codeforces.com/problemset/problem/893/E
題意:
共q組資料(q <= 10^5),每組資料給定x,y(x,y <= 10^6)。
問你有多少種長度為y,乘積為x的整數數列。(可以有負數)
題解:
首先考慮數列只有正整數的情況。
將x分解質因數:x = ∑ a[i]*p[i]
由於x較大,所以要先用線性篩求出素數,再列舉素數分解質因數。
那麼一個乘積為x的數列可以看做,將x的所有∑ p[i]個質因子,分配到了y個位置上。
設f(i)表示:將p[i]個質因子a[i],分配到y個位置上的方案數。
所以乘積為x的數列總數ans = ∏ f(i)。
其中,f(i)等價於:長度為y,和為p[i]的數列總數。
由於是多組資料,所以要預處理出對於所有長度的f(i)。
dp[i][j]表示y = i時,之和為j的數列總數。
轉移:dp[i][j] = ∑ dp[i-1][0 to j]
用字首和優化轉移,總複雜度O(nlogn)。
這樣就求出了只考慮正整數情況下的數列總數:ans = ∑ dp[y][p[i]]
然後考慮加負號的情況。
由於x為正數,所以只能加偶數個負號。
所以加負號的方案數 = C(y,0) + C(y,2) + C(y,4) + ... + C(y,偶數)
有一個組合數結論:∑ C(n,偶數) = ∑ C(n,奇數) = 2^(n-1)。
所以最終ans = ans * (2^(y-1))即為最終答案。
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #define MAX_X 1000005 5 #define MAX_P 25 6 #define SET_X 1000000 7 #define SET_P 20 8 #define MOD 1000000007 9 10 using namespace std; 11 12 int x,y,q; 13 int cnt,tot=0; 14 int p[MAX_P]; 15 int pw[MAX_X]; 16 int prime[MAX_X]; 17 int dp[MAX_X][MAX_P]; 18 int sum[MAX_X][MAX_P]; 19 bool mark[MAX_X]; 20 21 void cal_dp() 22 { 23 memset(dp,0,sizeof(dp)); 24 memset(sum,0,sizeof(sum)); 25 dp[0][0]=1; 26 for(int i=0;i<=SET_P;i++) sum[0][i]=1; 27 for(int i=1;i<=SET_X;i++) 28 { 29 for(int j=0;j<=SET_P;j++) 30 { 31 dp[i][j]=sum[i-1][j]; 32 sum[i][j]=(sum[i][j-1]+dp[i][j])%MOD; 33 } 34 } 35 } 36 37 void cal_pw() 38 { 39 pw[0]=1; 40 for(int i=1;i<=SET_X;i++) pw[i]=(pw[i-1]<<1)%MOD; 41 } 42 43 void sieve() 44 { 45 memset(mark,false,sizeof(mark)); 46 for(int i=2;i<=SET_X;i++) 47 { 48 if(!mark[i]) prime[++tot]=i; 49 for(int j=1;j<=tot && (long long)i*prime[j]<=SET_X;j++) 50 { 51 mark[i*prime[j]]=true; 52 if(!(i%prime[j])) break; 53 } 54 } 55 } 56 57 void resolve() 58 { 59 int t=x; 60 cnt=0; 61 memset(p,0,sizeof(p)); 62 for(int i=1;i<=tot && prime[i]*prime[i]<=x;i++) 63 { 64 if(t%prime[i]==0) 65 { 66 cnt++; 67 while(t%prime[i]==0) 68 { 69 t/=prime[i]; 70 p[cnt]++; 71 } 72 } 73 } 74 if(t!=1) p[++cnt]=1; 75 } 76 77 int cal_ans() 78 { 79 resolve(); 80 long long ans=1; 81 for(int i=1;i<=cnt;i++) ans=ans*dp[y][p[i]]%MOD; 82 return ans*pw[y-1]%MOD; 83 } 84 85 int main() 86 { 87 sieve(); 88 cal_dp(); 89 cal_pw(); 90 cin>>q; 91 while(q--) 92 { 93 cin>>x>>y; 94 cout<<cal_ans()<<endl; 95 } 96 }