HDU 5187 思维+快速幂模板

3 篇文章 0 订阅
2 篇文章 0 订阅

题目链接

题意

  • 给n个数字,从1到n,现在定义一种排列,满足一下两个条件

    • 从{1-i}的排列是单调排列
    • 从{i-n}的排列是单调排列
  • 给定n和p求这种排列的个数模上p的结果

解法

  • 如果i这个位置的数是不是1且不是n,那么只有从1-n的排列和从n到1的排列,有2种(其实包含在二和三中)
  • 如果是1那么能形成的排列是1的两边都是单调递减,因为所有的数都大于1,每个数都可能在1的左边或者右边,总共有2的 2^(n-1) 种
  • 同理,如果是n也是 2^(n-1) 种
  • 然后发现第二种情况与第三种情况完全包含了第一种情况 , 同时第二种和第三种情况有完全重合的地方,也就是1在最左边那么n肯定就在最右边,同时n在最左边那么1肯定就在最右边,有二种是重复的
  • 所以总的个数为 2^n - 2

注意

  • 这个题目的n和p相当的大,有10^18
  • 所以普通的快速幂是会爆的

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>
using namespace std ;

typedef long long LL ;

LL Mod ;

LL mul(LL n , LL k) {
    LL ans = 0 ;
    n %= Mod ;
    while(k) {
        if(k&1) {
            ans +=  n ;
            if(ans > Mod) ans -= Mod ;//此处
        }
        n <<= 1 ;
        if(n > Mod) n -= Mod ;//以及此处如果是去模运算700+ms ,减法则是70+ms
        k >>= 1 ;
    }
    return ans ;
}

LL pow_mul(LL n , LL k) {
    LL ans = 1 ;
    while(k) {
        if(k&1) ans = mul(ans , n) ;
        n = mul(n , n) ;
        k >>= 1 ;
    }
    return ans ;
}

int main() {
    LL n ;
    while(scanf("%I64d%I64d" , &n ,&Mod) == 2) {
        if(n == 1) {
            printf("%I64d\n" , n%Mod) ;
            continue ;
        }
        printf("%I64d\n" , (pow_mul(2 , n)-2+Mod)%Mod) ;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值