题目描述
作为史上最贪玩的宏志狗,chty已经数月没交数学作业了,而他在月考中数学考了146分,完爆了全班同学,保平认为自己遭到了光速打脸,于是他给chty出了n道题,教他做人。
chty认为第i道题的难度就是i,他想让这些题目排列起来很漂亮。
chty认为一个漂亮的序列{an}下列两个条件均需满足。
1:a1..ai是单调递减或者单调递增的。
2:ai..an是单调递减或者单调递增的。
他想你告诉他有多少种排列是漂亮的。因为答案很大,所以只需要输出答案模p之后的值。
数据组数<=1000 1<=n,p<=10^18
输入格式
输入数据若干组
每组数据一行两个整数:n,p
输出格式
每组数据输出排列的方案数模p的结果。
基于题意,ai必然是数列中的最大值or最小值。两种情况是一样的,我们考虑ai是最大值。那么对于剩下的 n-1 个数,都有两种选择,放在 ai 左边或者右边。也就是说这种情况共有 2^( n-1 ) 种排列方式,最小值同理,相加共有 2^n种,但是当整个序列单调递增or递减的两种排列被重复计算了1次,所以总排列方式为 2^n-2。
特别地,n=1时,排列方式=1。
数据这么大,显然要用到快速幂,带取模,还要用到快速乘。这两者也还是《进阶指南》讲的清楚明白,回头单写博客啦88!
#include<bits/stdc++.h>
using namespace std;
long long n,p;
long long mul_(long long a,long long b)
{
long long ans=0LL;
for(;b;b>>=1)
{
if(b&1) ans=(ans+a)%p;
a=(a<<1)%p;
}
return ans;
}
long long fast_power(long long a,long long b)
{
long long ans=1LL;
for(;b;b>>=1)
{
if(b&1) ans=mul_(ans,a);
a=mul_(a,a);
}
return ans;
}
int main()
{
while(cin>>n>>p)
{
if(n==1) printf("1\n");
else printf("%lld\n",(fast_power(2LL,n)-2+p)%p);
}
return 0;
}