【数论】contest - 题解

题面

     【数论】contest
【数论】contest - 题解_第1张图片
【数论】contest - 题解_第2张图片
        分析:首先题目的含义是,在 n n n 个位置上分别放入 1 ∼ n 1 \sim n 1n n n n 个数,使得在 某一个点 之前,序列满足单调递增或单调递减,在这个点之后,序列满足单调递增或单调递减。

       实际上我们可以枚举 每一个位置 x x x 作为 断点,分成两种情况讨论:

       1. 对于点 x x x 而言,它的 左侧单调递增 的,右侧单调递减

       2. 对于点 x x x 而言,它的 右侧单调递减的, 左侧单调递增

       那么有一个问题是,当 整个 序列 都是 单调递增 或 单调递减时,我们上述的方法会考虑到吗?

       再次考虑一下,当 x = 1 x = 1 x=1 时,情况 1 1 1 能考虑到 整个序列都是单调递减 的情况。 情况 2 2 2 则能考虑到 整个序列都是单调递增 的情况。

       而当 x = n x = n x=n 时,同样也会考虑到这两种情况,所以 这两种特殊情况不仅被考虑到了,而且分别被多考虑了一次,所以应该将多余答案 减去

       因为 断点不同,所以每种方案数都是不一样的,所以我们可以列出等式:


        r e s = ( ∑ i = 1 n g ( i ) + f ( i ) ) − 2 res = (\sum_{i = 1}^{n} g(i) + f(i)) - 2 res=(i=1ng(i)+f(i))2 (其中 g ( i ) g(i) g(i) f ( i ) f(i) f(i) 分别表示以 i i i 位置为断点,情况 1 1 1 和 情况 2 2 2 的方案数)。

       那么我们在考虑一下 g ( i ) g(i) g(i) f ( i ) f(i) f(i) 怎么算:

       对于 g ( x ) g(x) g(x) 而言,那么显然, x x x 这个位置必须要放上 n n n 这个数,因为在整个序列中它是最大的。而在它放过 n n n 后,剩余 n − 1 n - 1 n1 个数都是比它小的 ,我们只需要从中 任意 选出来 x − 1 x - 1 x1 个数字,通过一定的安排顺序,就可以满足位置 x x x 的前半部分, 而当我们选出来 x − 1 x - 1 x1 放在 x x x 位置的前面时, x x x 位置的前半部分 和 后半部分的数字摆放顺序其实已经确定。(因为 n n n 个数字 不一样 且要按严格的 递增 或 递减 顺序摆放),所以 g ( x ) = C n − 1 x − 1 g(x) = C_{n - 1}^{x - 1} g(x)=Cn1x1

       而求解 f ( x ) f(x) f(x) 的过程实际与求解 g ( x ) g(x) g(x) 的思路 一摸一样,只不过将 x x x 位置上的数换成 最小数 1 1 1,而答案实际也是 f ( x ) = C n − 1 x − 1 f(x) = C_{n-1}^{x - 1} f(x)=Cn1x1

       所以问题的答案也就变成了 r e s = 2 ∗ ∑ i = 1 n C n − 1 i − 1 − 2 res = 2 * \sum_{i = 1}^{n} C_{n - 1}^{i - 1} - 2 res=2i=1nCn1i12

       这个式子该如何化简呢?我们将式子展开写试试:

        r e s = 2 ∗ ( C n − 1 0 + C n − 1 1 + C n − 1 2 + C n − 1 3 + . . . + C n − 1 n − 1 ) − 2 res = 2 * (C_{n - 1}^{0} + C_{n - 1}^{1} + C_{n - 1}^{2} + C_{n - 1}^{3} + ... + C_{n - 1}^{n - 1}) - 2 res=2(Cn10+Cn11+Cn12+Cn13+...+Cn1n1)2

       我们发现和 二项式定理公式 很相似:

        ( a + b ) n = C n 0 a 0 b n + C n 1 a 1 b n − 1 + C n 2 a 2 b n − 2 + . . . + C n n a n b 0 (a + b)^n = C_{n}^{0} a^0b^n +C_{n}^{1}a^1b^{n - 1} +C_{n}^{2}a^2b^{n - 2} +... + C_{n}^{n}a^nb^0 (a+b)n=Cn0a0bn+Cn1a1bn1+Cn2a2bn2+...+Cnnanb0

       然后我们 a = b = 1 a = b = 1 a=b=1 ,则有:

       怎么样,是不是很 NB ,我们再次将思路回到原题:

       那么答案就是 r e s = 2 ∗ 2 n − 1 − 2 res = 2 * 2^{n - 1} - 2 res=22n12
                                     = 2 n − 2 = 2^n - 2 =2n2

       但是考虑到 模数很大,用快速幂直接乘会爆 l o n g l o n g long long longlong,所以我们再加一个 龟速乘。这样就能愉快的 AC 了!!

        CODE:

#include//答案 2^n - 2 
using namespace std;
typedef long long LL;
LL n, p;
LL mul(LL x, LL y, LL mod){//龟速乘
    LL res = 0; 
	while(y){
		if(y & 1) res = (res + x) % mod;
		x = (x + x) % mod;
		y >>= 1;
	}
	return res;
}
LL q_pow(LL x, LL y, LL mod){//快速幂
	LL res = 1;
	while(y){
		if(y & 1) res = mul(res, x, mod) % mod;
		x = mul(x, x, mod) % mod;
		y >>= 1;
	}
	return res;
}
int main(){
	freopen("contest.in", "r", stdin);
	freopen("contest.out", "w", stdout);
	while(~scanf("%lld%lld", &n, &p)){
		printf("%lld\n", (((q_pow(2, n, p) - 2) % p) + p) % p);
	}
	return 0;
}

你可能感兴趣的:(总结,算法,c++)