SGU 441:Set Division _第二类斯特林数

Description



Ruslan has K friends. And all of them have birthday tomorrow. He has bought N different photo albums yesterday, and wants to present these photo albums to his friends. Of course, he can't give less than 1 photo album to anybody. Your task is to calculate how many possible ways is there to do it.

All photo albums are different. Two distributions are considered the same if they differ only by order of albums in the gifts or by the persons receiving gifts.

Input

In the only line of the input there are two numbers separated by a space — , . , .



Output

Output should contain one number — the number of possible ways to distribute the albums modulo 2007.

Sample Input

sample input
sample output
3 2 
3


//题意其实就等同于将n个不同的球放进k个相等的盒子中,也就是第二类斯特林数。,   

//电大的一场比赛的题,前天在网络上同步比赛做的时候wrong了十几次,今天回过头来再做发现了题目数据n给的那么大没什么,主要在k那里埋下了一个重大的坑啊! k<=9的时候所有的数据都能跑过,但当k等于10的时候10!*2007>10^10。 那么在模幂运算的时候d=d*t%m,d*t已经超过了long long的数据范围,之前一直没有发现,一直wrong,看了电大大牛的代码分析才恍然大悟。那么在做乘法越界的情况下,就将乘转化为(加、减)取模运算。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
using namespace std;
#define LL __int64
#define inf 2007

LL Cal(LL x,LL y)
{
	LL ans=1,t=y;
	while(t--)
	{
		ans*=x,x--;
		while((ans%y==0)&&y>1)
			ans/=y,y--;
	}
	return ans;
}

LL mul_mod(LL a,LL b,LL m)  //(a*b)%m
{
	LL ans=0;
	LL d=a%m;
	while(b)
	{
		if(b&1)ans=ans+d;
		if(ans>=m)ans-=m;
		d<<=1;
		if(d>=m)d-=m;
		b>>=1;
	}
	return ans;
}

LL pow_mod(LL a,LL r,LL m)
{
	LL d=1,t=a%m;
	while(r)
	{
		if(r%2)
			d=mul_mod(d,t,m);   //(d*t)%m; ,d*t在m=10!*2007的情况下已经跃出long long
		r/=2;
		t=mul_mod(t,t,m)%m;
	}
	return d%m;
}

int main()
{
	LL n,k,i,j;
	while(~scanf("%I64d%I64d",&n,&k))
	{
		LL t=1,m=1,flag=1;
		for(i=1;i<=k;i++)
			t*=i;
		m=t*inf;    //(a/b)%m=(a%(b*m))/b。
		LL sum=0;
		for(i=0;i<=k-1;i++)
		{
			sum+=flag*Cal(k,i)*pow_mod(k-i,n,m);
			sum=(sum%m+m)%m;
			flag=-flag;
		}
		sum=sum%m/t;
		printf("%I64d\n",sum);
	}
	return 0;
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值