大连区域赛的铜牌题,虽然只是铜牌题我也想了好一会,感觉这场区域赛挺不好打呀。
贪心策略我是这样想出来的,先令n=25把,写成34567乘积最大,假如n被迫变小呢?34567->24567->23567->23467---->23456,这样最划算对吧,那么接下来?23456->3457,因为长度被迫-1了,and then,3457->3456->2456->2356---->2345,反正总以这个顺序往2345678.....的序列靠就对了。那么很简单,预处理这样连续串的和,对于每个询问,二分查找第一个比他大的是哪个串,然后找找规律,前缀积+逆元解决即可,复杂度(T*logn
#include <bits/stdc++.h>
#define LL long long
#define MAXN 50050
using namespace std ;
const int mod=1000000007;
LL sum[MAXN],inv[MAXN],add[MAXN];
void init()
{
inv[1]=1;
for(int i=2;i<MAXN;i++)
{
inv[i]=(mod-(mod/i))*inv[mod%i]%mod;
}
sum[2]=2;
add[2]=2;
for(int i=3;i<MAXN;i++)
{
sum[i]=sum[i-1]*1LL*i%mod;
add[i]=add[i-1]+1LL*i;
}
}
int main()
{
init();
int t;
scanf("%d",&t);
while(t--)
{
int n;
LL ans=0;
scanf("%d",&n);
int p=upper_bound(add,add+MAXN,n)-add;
if(n==add[p]) ans=sum[p];
else
{
int tmp=add[p]-n;
if(tmp==1) ans=((sum[p+1]*inv[2])%mod*inv[p])%mod;
else ans=(sum[p]*inv[tmp])%mod;
}
printf("%lld\n",ans);
}
return 0;
}
),详见代码。