【NOIP2012模拟10.26】电影票

本题规律难找:
我们可以这么想:
我们先求出所有的方案,然后在去掉不正确的方案即可。
所有的方案:C(n,n+m)
不正确的方案:C(m-1,(n+1)+(m-1))=C(m-1,n+m)
于是答案便为:

C(n,n+m)- C(m-1,n+m)

我们化简化简(#^ . ^#)

=(n+m)!/n!/m!-(n+m)!/(m-1)!/(n+1)!
=(n+m)!(n+1)/(n+1)!/m!-(n+m)!*m/m!/(n+1)!
=(n+m)!*(n-m+1)/(n+1)!/m!
=(n+2)x…x(n+m)*(n-m+1)/m!

这样我想时间复杂度应当是大大减小了。
然后压压位,这样便肯定不会时超了!

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define mo 100000000000000
using namespace std;
struct node {int len; ll a[2010];}ans,c;
int n,m;

node cheng(node a,ll y)
{
	c.len=a.len+2;
	ll x=0;
	for (int i=1;i<=c.len;i++)
	{
		c.a[i]=a.a[i]*y+x;
		x=c.a[i]/mo,c.a[i]%=mo;
	}
	while (!c.a[c.len]) c.len--;
	return c;
}

node divide(node a,ll y)
{
	c.len=a.len;
	ll x=0,h;
	for (int i=c.len;i>0;i--)
	{
		h=(a.a[i]+x)%y;
		c.a[i]=(a.a[i]+x)/y;
		x=h*mo;
	}
	while (!c.a[c.len]) c.len--;
	return c;
}

int main()
{
	freopen("movie.in","r",stdin);
//	freopen("movie.out","w",stdout);
	scanf("%d%d",&n,&m);
//	 C(n,n+m)-C(m-1,n+m)
//	=(n+m)!/m!/n!-(n+m)!/(m-1)!/(n+1)!
//	=(n+2)*...*(n+m)*(n-m+1)/m!
	ans.a[1]=n-m+1;ans.len=1;
	for (int i=n+2;i<=n+m;i++)
		ans=cheng(ans,i);
	for (int i=2;i<=m;i++)
		ans=divide(ans,i);
	printf("%lld",ans.a[ans.len]);
	for (int i=ans.len-1;i>0;i--)
		printf("%014lld",ans.a[i]);
	return 0;
}
posted @ 2019-01-05 15:21  jz929  阅读(141)  评论(0编辑  收藏  举报