Maximum Value Problem FZU 2037 找规律 递推

来源:互联网 发布:windows 锁屏快捷键 编辑:程序博客网 时间:2024/05/17 19:56

题目:https://cn.vjudge.net/problem/FZU-2037

题意:给出一个序列,由1~n这n个数组成,给出一个最大值Max,初始化为零。问按照题目给出的代码求这个序列的最大值需要更新多少次Max,将这个值暂记为m。题目所求该序列的所有排列的m的总和summ,以及summ/该序列总排列个数。

举个例子:
n = 3时
序列{1, 2, 3} —— m = 3
序列{1, 3, 2} —— m = 2
序列{2, 1, 3} —— m = 2
序列{2, 3, 1} —— m = 2
序列{3, 1, 2} —— m = 1
序列{3, 2, 1} —— m = 1
summ = 11
summ / 排列数 = 11 / 6 = 1.833333

思路
这题需要递推,从1推向n。
显然初始条件summ(1) = 1
从n-1推向n有两种情况
(1)n这个数放在原序列的最后,因为n就是最大的数,所以对于原序列每个m都要多更新一次,原序列一共有(n - 1)种排列
那么第一种情况summ1(n) = summ(n - 1) + 1 * (n - 1)!
(2)n这个数放在其他地方
n = 3,n-1 = 2时

1,2 = 2
2,1 = 1

3,1,2 = 1
1,3,2 = 2

3,2,1 = 1
2,3,1 = 2

n = 4,n-1 = 3时,如图
这里写图片描述

可以多写几组,注意观察,颜色相同的序列,它们的最后一位的数字都相同,它们每组的summ都为summ(n-1),共有n-1组
那么第二种情况summ2(n) = summ(n - 1) * (n - 1)

综上,总递推式
summ(n)
= summ(n-1) + (n-1)! + summ(n-1)*(n-1)
= n*summ(n-1) + (n-1)!

那么第二个结果问题可以根据以上递推式除上个n!可以推出
ans2(n) = ans2(n-1) + 1.0 / ans2(n-1)

别忘了处理取模

代码

//GNU C++上%lld会WA//需用%I64d#include <cstdio>#include <iostream>#include <cmath>#include <algorithm>#include <vector>using namespace std;const int maxn = 1000000 + 10;const long long MOD = 1000000007;long long fact[maxn];long long val[maxn];double ans[maxn];void init(){    fact[1] = 1;    for(int i = 2;  i < maxn; i++)    {        fact[i] = fact[i - 1] * i % MOD;    }    val[1] = 1;    for(int i = 2;  i < maxn; i++)    {        val[i] = i * val[i - 1] % MOD;        val[i] += fact[i - 1];        val[i] %= MOD;    }    ans[1] = 1;    for(int i = 2; i < maxn; i++)    {        ans[i] = ans[i - 1] + 1.0 / i;    }}int main(){    init();    int cases = 1;    int T;    cin >> T;    while(T--)    {        int n;        scanf("%d", &n);        printf("Case %d: %I64d %.6f\n", cases++, val[n], ans[n]);    }    return 0;}
原创粉丝点击