Description
对于一个集合TTT,定义mindiff(T)mindiff(T)mindiff(T)为TTT中任意两元素差值最小值,maxdiff(T)maxdiff(T)maxdiff(T)为TTT中任意两元素差值最大值,如果集合元素少于两个则定义两者值为000. 对集合{1,2,...,n}\{1,2,...,n\}{1,2,...,n}的所有子集TTT的mindiff(T)⋅maxdiff(T)mindiff(T)\cdot maxdiff(T)mindiff(T)⋅maxdiff(T)求和
Input
一个整数n(1≤n≤5⋅105)n(1\le n\le 5\cdot 10^5)n(1≤n≤5⋅105)
Output
输出答案,结果模109+710^9+7109+7
Sample Input
3
Sample Output
8
Solution
记mn(T)mn(T)mn(T)为集合TTT中任意两元素差值最小值,mx(T)mx(T)mx(T)为集合TTT中任意两元素差值最大值,对于集合TTT,假设其mn(T)=dmn(T)=dmn(T)=d,那么mx(T)mx(T)mx(T)对答案的贡献是ddd倍,进而考虑所有mn(S)≥dmn(S)\ge dmn(S)≥d的集合SSS的mxmxmx值之和,那么mx(T)mx(T)mx(T)在mx(S)≥1,...,dmx(S)\ge 1,...,dmx(S)≥1,...,d时都会被算一遍,也即算了ddd遍,故答案为∑d=1n−1f(d)\sum\limits_{d=1}^{n-1}f(d)d=1∑n−1f(d),其中f(d)f(d)f(d)为所有mn(S)≥dmn(S)\ge dmn(S)≥d的集合SSS的mxmxmx值之和,现在求f(d)f(d)f(d),枚举集合TTT的元素个数kkk和mx(T)=tmx(T)=tmx(T)=t,那么在111~nnn中选出最小值和最大值使得两者差值为ttt的方案数为n−tn-tn−t种,而在两者之间的t−1t-1t−1个位置中,为保证任意两个数字之间距离不小于d−1d-1d−1,由插板法,提前拿出(k−1)(d−1)(k-1)(d-1)(k−1)(d−1)个位置空着,在剩余位置中选取k−2k-2k−2个位置放剩下数字,故有
f(d)=∑k=2n∑t=1n−1t(n−t)Ct−1−(k−1)(d−1)k−2
f(d)=\sum\limits_{k=2}^n\sum\limits_{t=1}^{n-1}t(n-t)C_{t-1-(k-1)(d-1)}^{k-2}
f(d)=k=2∑nt=1∑n−1t(n−t)Ct−1−(k−1)(d−1)k−2
注意到为使组合数合法,需要修改k,dk,dk,d的下限,进而有
f(d)=∑(k−1)d≤n∑t=(k−1)dn−1t(n−t)Ct−1−(k−1)(d−1)k−2
f(d)=\sum\limits_{(k-1)d\le n}\sum\limits_{t=(k-1)d}^{n-1}t(n-t)C_{t-1-(k-1)(d-1)}^{k-2}
f(d)=(k−1)d≤n∑t=(k−1)d∑n−1t(n−t)Ct−1−(k−1)(d−1)k−2
由于满足(k−1)d≤n(k-1)d\le n(k−1)d≤n的(k,d)(k,d)(k,d)组数只有O(nlogn)O(nlogn)O(nlogn)规模,只需快速求出
∑t=(k−1)dn−1t(n−t)Ct−1−(k−1)(d−1)k−2
\sum\limits_{t=(k-1)d}^{n-1}t(n-t)C_{t-1-(k-1)(d-1)}^{k-2}
t=(k−1)d∑n−1t(n−t)Ct−1−(k−1)(d−1)k−2
在mathematicamathematicamathematica里跑一下有
∑t=(k−1)dn−1t(n−t)Ct−1−(k−1)(d−1)k−2=(n−1+2d)(n−(k−1)d)(n−(k−1)(d−1))k(k+1)Cn−1−(k−1)(d−1)k−2
\sum\limits_{t=(k-1)d}^{n-1}t(n-t)C_{t-1-(k-1)(d-1)}^{k-2}=\frac{(n-1+2d)(n-(k-1)d)(n-(k-1)(d-1))}{k(k+1)}C_{n-1-(k-1)(d-1)}^{k-2}
t=(k−1)d∑n−1t(n−t)Ct−1−(k−1)(d−1)k−2=k(k+1)(n−1+2d)(n−(k−1)d)(n−(k−1)(d−1))Cn−1−(k−1)(d−1)k−2
故可以O(1)O(1)O(1)求出该求和式,总时间复杂度O(nlogn)O(nlogn)O(nlogn)
Code
#include<cstdio>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f,maxn=500005;
#define mod 1000000007
int inv[maxn],fact[maxn],sum[maxn];
int add(int x,int y)
{
x+=y;
if(x>=mod)x-=mod;
return x;
}
int mul(int x,int y)
{
ll z=1ll*x*y;
return z-z/mod*mod;
}
void init(int n=500001)
{
inv[1]=1;
for(int i=2;i<=n;i++)inv[i]=mul(mod-mod/i,inv[mod%i]);
sum[0]=1;
for(int i=1;i<=n;i++)sum[i]=mul(sum[i-1],inv[i]);
fact[0]=1;
for(int i=1;i<=n;i++)fact[i]=mul(fact[i-1],i);
}
int C(int n,int m)
{
if(n<0||m<0||m>n)return 0;
return mul(fact[n],mul(sum[m],sum[n-m]));
}
int main()
{
init();
int n;
scanf("%d",&n);
int ans=0;
for(int d=1;d<=n-1;d++)
for(int k=2;(k-1)*d<=n&&k<=n;k++)
{
int w=n-(k-1)*(d-1);
int res=C(w-1,k-2);
res=mul(mul(res,n-1+2*d),mul(inv[k],inv[k+1]));
res=mul(res,mul(w-(k-1),w));
ans=add(ans,res);
}
printf("%d\n",ans);
return 0;
}