题解 P1595 【信封问题】

分类: asiasports365 作者: admin 时间: 2025-09-14 09:30:01 阅读: 4153
题解 P1595 【信封问题】

题解 P1595 【信封问题】

杨戬大师

·

2019-08-29 15:06:23

·

题解

这道题我一上来就开始思考每一组数据之间的关系,如果发现了关系,就可以通过递推的方式求出答案了。

假如现在有 n 个信封和信,那么我把答案记为 Sn。不难发现这个Sn是这样构成的:先是不管每一个信装没装错,那么一共有 n! 种组成方式。但是这 n! 显然多了,那么我就减掉那些多的。

这是求 n! 的代码:

long long jc(int x)

{

long long ans = 1, i;

for (i = 2; i <= x; i++)

ans *= i;

return ans;

}

那么多的是如何构成的呢?多的是有一些信封的位置是对的,而剩下的是错的。所以不管那些对的,那些错的有多少种组成方式我们之前已经算出来了!只不过它们有可能再一些不同的位置上,所以我们再在每个 Sn-1 到 S1 前面乘一个系数,这系数便是它有可能在几种位置上,用一个排列组合中的组合就行了。其实就是那个我们所熟知的C。

求组合C的代码:

long long C(int x, int y)//组合函数

{

long long ans = 1, i;

y = min(y, x - y);

for (i = x; i > x - y; i--)

ans *= i;

for (i = y; i > 0; i--)

ans /= i;

return ans;

}

按如上方法算完多的以后,就用 n! 减去那些多的,便是每一层的答案了,然后再一路递推,就可以推出答案了。

感觉我说的不太清楚,可以看看代码是如何写的。

AC代码:

#include

#include

using namespace std;

long long jc(int x)

{

long long ans = 1, i;

for (i = 2; i <= x; i++)

ans *= i;

return ans;

}

long long C(int x, int y)//组合函数

{

long long ans = 1, i;

y = min(y, x - y);

for (i = x; i > x - y; i--)

ans *= i;

for (i = y; i > 0; i--)

ans /= i;

return ans;

}

long long s[21];

int main()

{

int n, i, j;

scanf("%d", &n);

for (i = 2; i <= n; i++)

{

s[i] = jc(i) - 1;

for (j = i - 1; j > 1; j--)

s[i] -= s[j] * C(i, j);

}

printf("%lld", s[n]);

return 0;

}

相关推荐