hdu 5187 zhx and contest(快速幂、快速乘法)

问题描述

作为史上最强的刷子之一,zhx的老师让他给学弟(mei)们出n道题。
zhx认为第i道题的难度就是i。他想要让这些题目排列起来很漂亮。
zhx认为一个漂亮的序列{ai}下列两个条件均需满足。
1:a1..ai是单调递减或者单调递增的。
2:ai..an是单调递减或者单调递增的。
他想你告诉他有多少种排列是漂亮的。
因为答案很大,所以只需要输出答案模p之后的值。

输入描述

多组数据(不多于1000组)。读到文件尾。
每组数据包含一行两个整数n和p。(1≤n,p≤10^18)

输出描述

每组数据输出一行一个非负整数表示答案。

输入样例

2 233
3 5

输出样例

2
1

Hint

第一组数据中{1, 2}和{2, 1}合法。
第二组数据中{1, 2, 3}, {1, 3, 2}, {2, 1, 3}, {2, 3, 1}, {3, 1, 2}, {3, 2, 1}都合法,所以答案是6 mod 5 = 1。

 

 

分析:

1、首先考虑序列单调递增、递减,这是两种符合条件的序列。

2、序列先单调递减,然后递增。

此时考虑最小的数a[i]的位置。

然后若a[i]放在第2位,则第1个位置有C(n-1,1)种选择。即从剩下的n-1个数中选1个放在a[i]左边,其余的放在a[i]右边呈递增排列。

a[i]放在第3位,则前两个位置有C(n-1,2)种选择。

……

a[i]放在第n-1位,前n-2个位置有C(n-1,n-2)种选择。

总共有C(n-1,1)+C(n-2,1)+……+C(n-1,n-2)种不同的序列

3、序列先单调递增,然后递减,同上考虑即可。

 

因此漂亮序列的总数是:

2*(C(n-1,1)+C(n-2,1)+……+C(n-1,n-2))+2

=2*(C(n-1,0)+C(n-1,1)+C(n-2,1)+……+C(n-1,n-2)+C(n-1,n-1)-2)+2

=2*(2^(n-1)-2)+2

=2^n-2

 

由于这里的p可以非常大,如果直接采用快速幂的做法,n%p*n%p的结果将会超出long long 的范围。

必须使用快速乘法来解决。其原理和快速幂一样,都是二进制的原理。

对于a*b%c,设b=2^k1+2^k2+……

则a*b%c=a*(2^k1+2^k2+……)%c

         =(a*2^k1%c+a*2^k2%c+……)%c

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define LL long long
LL mul(LL a,LL b,LL mod)
{
    a %= mod;
    b %= mod;
    LL ans = 0;
    while(b)
    {
        if(b & 1)
        {
            ans += a;
            if(ans >=mod)ans -= mod;//比直接取模快
        }
        a <<= 1;
        if(a >=mod)a -= mod;
        b >>= 1;
    }
    return ans;
}
LL pow(LL a,LL b,LL mod)
{
    LL ans=1;
    while(b)
    {
        if(b&1LL) ans=mul(ans,a,mod);
        b>>=1LL;
        a=mul(a,a,mod);
    }
    return ans;
}
int main()
{
    LL n,p,ans;
    while(scanf("%I64d %I64d",&n,&p)!=EOF)
    {
        if(n==1) ans=1;
        else ans=pow(2,n,p)-2+p;
        printf("%I64d\n",ans%p);
    }
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值