Newcoder 145 F.Mindiff and Maxdiff(组合数学)

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}的所有子集TTTmindiff(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(1n5105)

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的集合SSSmxmxmx值之和,那么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=1n1f(d),其中f(d)f(d)f(d)为所有mn(S)≥dmn(S)\ge dmn(S)d的集合SSSmxmxmx值之和,现在求f(d)f(d)f(d),枚举集合TTT的元素个数kkkmx(T)=tmx(T)=tmx(T)=t,那么在111~nnn中选出最小值和最大值使得两者差值为ttt的方案数为n−tn-tnt种,而在两者之间的t−1t-1t1个位置中,为保证任意两个数字之间距离不小于d−1d-1d1,由插板法,提前拿出(k−1)(d−1)(k-1)(d-1)(k1)(d1)个位置空着,在剩余位置中选取k−2k-2k2个位置放剩下数字,故有
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=2nt=1n1t(nt)Ct1(k1)(d1)k2
注意到为使组合数合法,需要修改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)=(k1)dnt=(k1)dn1t(nt)Ct1(k1)(d1)k2
由于满足(k−1)d≤n(k-1)d\le n(k1)dn(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=(k1)dn1t(nt)Ct1(k1)(d1)k2
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=(k1)dn1t(nt)Ct1(k1)(d1)k2=k(k+1)(n1+2d)(n(k1)d)(n(k1)(d1))Cn1(k1)(d1)k2
故可以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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值