Atcoder 800 Painting Machine 数学(计数)

题意:n个白球.n-1台机器,第i台机器会将第(i,i+1)的球变为黑色.
一个操作序列为[1..n-1]的排列,其价值定义为n个球第一次变为黑色的时间.
2<=n<=1e6. 给出n,问所有操作排列,其价值总和模1e9+7 ?


看了题解..先膜下rng_58.

计算价值<=k的排列有多少个? 那么价值为k的就是d[k]-d[k-1]
首先1,n-1这两台机器必选,否则1,n不会变成黑色.
假设1=a[1]<a[2]<.....a[k] =n-1  那么a[i]-a[i-1]的间隔为1或者2. 设这两个个数为a,b.
可以得 a+b=k-1 ,  a+2b=n-2  解得b=n-k-1 那么从k-1个间隔中选b个为间隔2,就可以确定一个方案.方法数为C(k-1,n-k-1)

那么价值为k的排列总个数为: C(k-1,n-k-1) * k! * (n-1-k) !.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5,mod=1e9+7;
ll n,f[N];
ll powmod(ll x,ll n)
{
	ll s=1;
	while(n)
	{
		if(n&1)
			s=(s*x)%mod;
		n>>=1;
		x=(x*x)%mod;
	}
	return s;
}
ll C(ll n,ll m)
{
	if(n<m)
		return 0;
	ll a=f[n],b=(f[n-m]*f[m])%mod;
	return (a*powmod(b,mod-2))%mod;
}
int main()
{
	cin>>n;
	f[0]=1;
	for(int i=1;i<=n;i++)
		f[i]=(f[i-1]*i)%mod;
	ll res=0,pre=0;
	for(int k=1;k<n;k++)
	{
		ll tk=(f[k]*f[n-1-k])%mod;
		tk=(tk*C(k-1,n-k-1))%mod;
		ll num=(tk-pre+mod)%mod;
		res=(res+(num*k)%mod)%mod;
		pre=tk;
	}
	cout<<res<<'\n';
	return 0;
}


计数的时候可以先假定有序,算出其方案.然后在排列


猜你喜欢

转载自blog.csdn.net/noone0/article/details/80209951
今日推荐