题目描述:点击打开链接
题意也很简单,不解释。其实这题脑洞做法并不是我想出来的,队友想出来的做法我只负责了代码实现而已,关于做法,这题的分割方案举个例子比如7,7=2+3,后面加不了4了,并且还多出2那么我开始从3开始倒着每个数+1变成7=3+4所以答案就是3*4=12,在比如17=2+3+4+5,这是加不了6,并且还差3那么我们就把这3倒着每个数+1变成17=2+4+5+6,所以答案就是2*4*5*6=240,这样应该是解释的比较清楚了,那么讨论一下特殊情况就是我们从2开始累加完之后,还差的数字把每个数都加了1之后还差,比如13=2+3+4这里加不了5,那么把还差的4倒着每个数加1之后变成13=3+4+5这个时候还差1,那么就变成3+4+6这就是最终的答案,并且我们会发现这就是最极限的情况了,最多就是最后一个数+2,其他数都+1不会出现倒数第二个数甚至更前面的数+2的情况。那么讨论完做法之后,关于具体的实现,我们可以先把累加和打个表把阶乘也打个表,每次找到第一个大于该数x的位置然后-1就找到了前面有几个数,然后求出求出还差多少,讨论一下这个差值的情况如果不会出现最后一个数+2的情况的话那么只需要找到+1的最前面的一个位置就可以了,比如17我们找到2+3+4+5发现差2,补完之后是2+3+5+6实际上就是6!/4。而对于最后一个数+2的情况其实就是原来最后一个数+2的阶乘除2和原来最后最后一个数+1,比如13一开始我们找到2+3+4最后补完是3+4+6实际上就是6!/2*5。最后关于除法取模的问题,用费马小定理求一下逆元就好了。
AC代码:
#include<iostream>
#include<sstream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<vector>
#include<stack>
#include<queue>
#include<algorithm>
using namespace std;
const long long MOD=1e9+7;
const int MAXM=45000;
long long x;
long long sum[MAXM+10];
long long mul[MAXM+10];
void init()
{
sum[1]=0;
for (long long i=2;i<=MAXM;i++)
sum[i]=(sum[i-1]+i);
mul[1]=1;
for (long long i=2;i<=MAXM;i++)
mul[i]=(mul[i-1]*i)%MOD;
}
long long qpow(long long x,long long y)
{
long long res=1;
while(y) {
if (y&1) res=(res*x)%MOD;
x=(x*x)%MOD;
y=y>>1;
}
return res;
}
int main()
{
int T;
scanf("%d",&T);
init();
while(T--)
{
scanf("%lld",&x);
if (x==1) {
printf("1\n");
continue;
}
int index=upper_bound(sum+2,sum+2+MAXM+10,x)-sum;
// cout<<index<<endl;
index--;
// cout<<index<<endl;
long long sub=x-sum[index];
//cout<<sub<<endl;
long long ans;
if (sub==(long long)(index-1)) {
ans=mul[index+1]*(qpow(2,MOD-2)%MOD)%MOD;
}
else if (sub==(long long)index) {
ans=(mul[index+2])%MOD*qpow(2*(index+1)%MOD,MOD-2)%MOD;
//cout<<ans<<endl;
}
else {
ans=(mul[index+1])%MOD*qpow(index-sub+1,MOD-2)%MOD;
}
printf("%lld\n",ans);
}
return 0;
}