传送门
题目大意:
作为史上最强的刷子之一,zhx的老师让他给学弟(mei)们出 n 道题。 zhx认为第i道题的难度就是 i 。他想要让这些题目排列起来很漂亮。 zhx认为一个漂亮的序列{ai}下列两个条件均需满足。 1: a1..ai 是单调递减或者单调递增的。 2: ai..an 是单调递减或者单调递增的。 他想你告诉他有多少种排列是漂亮的。 因为答案很大,所以只需要输出答案模 p 之后的值。
解题思路:
首先我们将题目给定的条件在细化一下: (1): a1..ai 是单调递增的,那么 ai..an 一定是单调递减的,而且 ai=n 。 (2) : a1..ai 是单调递减的,那么 ai..an 一定是单调递增的,而且 ai=1 。 将条件细化成这样之后就好想多了,其实 (1) 和 (2) 是没有什么区别的,就拿第一个来说,因为 ai=n 这是确定的,所以只需要确定 i 的位置就行啦,确定好 i 的位置之后,剩下的就是简单的组合数学了,假设 n=5 ,那么 i 的位置有 5 个,刨除掉 1 ,还有 4 个数 i=1:那么符合条件的有C04个 i=2:那么符合条件的有C14个 i=3:那么符合条件的有C24个 i=4:那么符合条件的有C34个 i=5:那么符合条件的有C44个 所以总数是 24 根据二项式定理,那么满足第 (2) 个条件的也有 24 个,但是中间有重复的,就是单调递增的和单调递减的多算了以此,所以减 2 ,总数就是 24∗2−2,可以推出这个题的总的方法数就是 2n−1∗2−2 , 即 2n−2 ,还需要注意的问题就是,这个取模的数太大,所以在进行快速幂的时候不要直接乘,要进行快速乘法。
MyCode:
#include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> using namespace std; typedef long long LL; LL n, MOD; LL Multi_mod(LL a, LL b){ LL ans = 0; while(b){ if(b & 1LL) ans = (ans + a) % MOD; b>>=1LL; a = (a + a) % MOD; } return ans; } LL Pow_mod(LL a, LL b){ LL ans = 1LL; a %= MOD; while(b){ if(b & 1LL) ans = Multi_mod(ans, a); b>>=1LL; a = Multi_mod(a, a); } ans = (ans-2LL) % MOD; ans = (ans % MOD + MOD) % MOD; return ans; } int main(){ while(~scanf("%lld%lld",&n,&MOD)){ if(n == 1LL){ if(MOD == 1) puts("0"); else puts("1"); continue; } printf("%lld\n",Pow_mod(2LL, n)); } }