數論 UVALive-7728 Detachment 階乘逆元
In a highly developed alien society, the habitats are almost infinite dimensional space. In the history of this planet,there is an old puzzle.
You have a line segment with x units’ length representing one dimension. The line segment can be split into a number of small line segments: a1, a2, . . . (x = a1+a2+. . . ) assigned to different dimensions. And then, the multidimensional space has been established.
Now there are two requirements for this space:
1. Two different small line segments cannot be equal (ai ̸= aj when i ̸= j).
2. Make this multidimensional space size s as large as possible (s = a1 ∗ a2 ∗ . . .).
Note that it allows to keep one dimension. That’s to say, the number of ai can be only one.
Now can you solve this question and find the maximum size of the space? (For the final number is too large,your answer will be modulo 109 + 7)
Input
The first line is an integer T, meaning the number of test cases.
Then T lines follow. Each line contains one integer x. 1 ≤ T ≤ 106 , 1 ≤ x ≤ 109
Output
Maximum s you can get modulo 109 + 7.
Note that we wants to be greatest product before modulo 109 + 7.
Sample Input
1
4
Sample Output
4
題目大意:
轉換一下,即,將一個數字x,分成任意不同數字相加的和,求這些數字的最大乘積。
首先,一定條件下,能夠分多一點的話乘積會大。通過手動打表找規律,發現 2 * ……(k個)……* (k+1)是分解成k個數相乘的第一個數。所以我們可以通過給定的x算出它應該分成k個數字使乘積最大。
然後我們可以算出多出的add,即x-分解成k個數乘積的第一個數。從最後一個數往前每個數+1可使乘積最大。注意特殊情況,add=k+1時,應使最後一個數+2。
注意特判1的情況。
然後寫完t了,因為T太大,就先預處理出階乘,以及階乘的逆。有模數所以做除法的時候要轉化為乘它的逆。
單獨放一下預處理的程式碼:
fac[0] = 1;
for(int i = 1; i <= maxk; i++)
fac[i] = (fac[i - 1] * i) % mod;
inv[maxk] = qpow(fac[maxk], mod - 2);
for(int i = maxk - 1; i >= 0; i--)
inv[i] = (inv[i + 1] * (i + 1)) % mod;
如上真的非常神奇啊。
應用了費馬小定理:
在模為素數p的情況下,a^(p-1)=1(mod p);
那麼 a^(p-2)=a^-1(mod p),也就是說a的逆元為 a^(p-2)。
階乘逆元就倒著來嘛(求逆是變相除法這樣想的話就能感受到了)
最後,注意記得各種模!
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const long long mod=1e9+7;
const int maxk=1e6;
long long x,k;
long long s;
long long fac[maxk+1],inv[maxk+1];
long long qpow(long long x,long long n)
{
long long ans=1;
while(n){
if(n&1){
ans*=x;
ans%=mod;
}
n>>=1;
x*=x;
x%=mod;
}
return ans;
}
void pre()
{
fac[0] = 1;
for(int i = 1; i <= maxk; i++)
fac[i] = (fac[i - 1] * i) % mod;
inv[maxk] = qpow(fac[maxk], mod - 2);
for(int i = maxk - 1; i >= 0; i--)
inv[i] = (inv[i + 1] * (i + 1)) % mod;
}
int main()
{
int T;
scanf("%d",&T);
/*
t[0]=1;
for(int i=1;i<=maxk;++i){
t[i]=t[i-1]*i;
t[i]%=mod;
}
inv[maxk]=qpow(t[maxk],mod-2);
for(int i=maxk-1;i>=0;--i){
inv[i]=inv[i+1]*(i+1);
inv[i]%=mod;
}
*/
pre();
//for(int i=0;i<25;++i){printf("%d fac:%lld inv:%lld\n",i,fac[i],inv[i]);}
while(T--){
s=1;
scanf("%lld",&x);
if(x==1){
printf("1\n");
continue;
}
double cal=sqrt(2*x+9*1.0/4)-1.5;
k=(long long)cal;
long long sum=k*(k+3)/2;
long long add=x-sum;
if(add<=k){
s*=fac[k+1-add]%mod;
s%=mod;
s*=fac[k+2]%mod*inv[k+2-add]%mod;
s%=mod;
}
else if(add==k+1){
s*=fac[k+1]%mod*(k+3)%mod*inv[2]%mod;
s%=mod;
}
printf("%lld\n",s);
}
return 0;
}