问题描述
作为史上最强的刷子之一,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; }