hdu 5187 zhx's contest(快速幂+快速乘)

96 篇文章 0 订阅
20 篇文章 0 订阅

题意:

给一个1-n的序列,问有多少中排列方式,使这个序列中存在一个点,它的两边分别满足升升,升降,降降,降生,n的范围是1e18, 答案对p取模,范围是1e18.


解题思路:

一个点能满足左边的数(包括自己)单调递增,自己右边的数(包括自己)单调递减,那么这个数只能是最大值,反之只能是最小值,而我们要求的是就是除开最值之外的排布方案,对于最大值来说,n-1个数每个数只有两种可能,要么排在最大值左边,要么排在最大值右边,所以方案数是2的n-1次,而最小值也是2的n-1次,两种情况加在一起是2的n次.但是考虑一个数两边同时是增或同时是减的情况,我们有没有必要单独算呢?

答案是不用,因为在求增减,减增的时候,剩下的n-1一个数如果都排布在最值的一侧,就能得到升升序列和降降序列了,但是这两种序列在求升降,降升序列的时候都被计算了一次,所以最后答案需要-2,公式就是2的n次-2.

到这里题目的解法都得到了,但是在代码实现上我们来分析,首先2的n次取模肯定要用快速幂,而快速幂里用到乘法,题目给的数据范围是1e18,两个1e18的数相乘不就要爆longlong了,所以我们需要用的一个新的技能(对于弱来说),快速乘,具体原理和快速幂是相同的.就是把乘法化为加法,然后只加二进制中位数为一对应的数进行加快速度.具体见代码


代码:

#include <bits/stdc++.h>
using namespace std;

long long qmutip(long long m, long long n, long long mod)
{
    long long res=0;
    while(n>0)
    {
	if(n&1)
	   res=(res+m)%mod;
	m=(m+m)%mod;
	n>>=1;
    }
    return res%mod;

}
long long quickmod(long long a, long long k, long long mod)
{
    long long res=1;
    while(k>0)
    {
       if(k&1)
	 res=qmutip(res, a, mod);
       a=qmutip(a,a, mod);
       k>>=1;
    }
    return res%mod;
}
int main()
{
    long long n, p;
    while(~scanf("%lld %lld", &n, &p))
    {
	printf("%lld\n", (quickmod(2, n, p)-2+p)%p);
    }
     
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值