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;
}



你可能感兴趣的:(网络,less,input,代码分析,output,Numbers)