传球问题

传球问题
Time Limit:1000MS Memory Limit:30000KB

Description 

排球课上,老师进行在共青场进行传球练习,一共有p人参加,一开始球在你的手里。每次传球时,持球者都会把球传给另外一个人。传了n次后,球又回到了你的手里。现在老师想知道有多少种传法,他说如果给出答案,会有奖励的。于是大家各自开动大脑,想办法解决。作为计算机系的你,想要写一个程序来解这个问题……

提示:
例如,对于p=4,n=4,有21种传法。设四人分别为甲、乙、丙、丁,你是甲。若第一次球传给乙,则有以下7种传法:甲乙甲乙甲,甲乙甲丙甲,甲乙甲丁甲,甲乙丙乙甲,甲乙丙丁甲,甲乙丁乙甲,甲乙丁丙甲。若第一次传给丙和丁,同理各有7种传法。共计21种。

Input 

本题有多组测试数据。
每组数据一行,每行有两个整数p和n。其中,2<=p<=1000000,2<=n<=2^31-1。
当一行中的p和n都为0时,输入结束。

Output 

每组数据输出一行,每行一个整数。因为数字可能会非常大,所以你只要输出总数除2005的余数即可。

Sample Input 

4 4
4 10
1000 1000
0 0

Sample Output 

21
728
1



这道题是一个组合数学问题,碰到这题我们的第一想法肯定是如果能找出递推公式,应该就能解决问题。可是递推公式不是很好找,还是要仔细分析下题目的。可以用个数组表格来模拟下这道题,如下图所示:


假设用f(n)表示传了n次的方案数,从题目中很容易看出,相邻的两个不能一样,因此第n-1次不能传到"你"手里。
我们来分析下,找到f(n)的递推公式,影响f(n)的有两种情况:
#1:若n-1位置和首位相同,则n-1位置定死了就一种选择,则f(n)=f(n-2)*(p-1)
#2:  若n-1位置和首位不相同,则n位置不能和首位相同,并且不能和n-1位置选择相同,则f(n)=f(n-1)*(p-2)

因此,综上所述,f(n) = f(n-2)*(p-1) + f(n-1)*(p-2)

但是题目给的p和n非常的大,而且也提示了让去2005的模,因此f(n) =(((p-1)%2005)*f(n-2) + ((p-2)%2005)*f(n-1)%2005即可。
而且基本上涉及到取模,肯定会有循环发生,因此我们没必要算出所有数,找到循环即可。不然数组f定义的过大,内存要超。

下面给出代码:

#include <iostream>
#include <cstring>
using namespace std;
const int m = 2005;
short f[3000];
int main()
{
    int p,n;
    while(cin >> p >> n)
    {
        if(p == 0 && n == 0)
        {
            break;
        }
        memset(f,0,sizeof(f));
        f[1] = 0;
        f[2] = (p-1)%m;
        int i;
        for(i = 3; i <= n; ++i)
        {
            f[i] = (((p-1)%m)*f[i-2] + ((p-2)%m)*f[i-1])%m;
            if(f[i-1] == f[1] && f[i] == f[2])//产生循环即可跳出
            {
                break;
            }
        }
        if(n > i)//循环
        {
            int c = i-2;//求得循环长度
            int ans = n%c;
            if(ans == 0)
            {
                ans = c;
            }
            cout << f[ans] << endl;
        }
        else//n比i小,直接输出
        {
            cout << f[n] << endl;
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值