• C. Tourist Problem 2021.3.29 晚vj拉题 cf 1600 纯数学题


     

    拉题链接  https://vjudge.net/contest/430219#overview

    原题链接  https://codeforces.com/problemset/problem/340/C

    前言

    cf 1600的题, 直接拿来给大一的做, 感觉有亿点点难, 这是个纯数学题, 我用的排列组合方法推导

    题目

     

    题意(其实我觉得还是看上边的Note好理解)

    给n个数(分别为a1, a2 ...... an-1, 把这n个数全排(共Ann 个序列)一遍, 对于每个序列, 值=每个|ai - ai-1|之和(i = 1~n) , 其中, i = 0时, 为|a1-0| 

    然后, 将这n的阶乘个式子的值加起来, 先用res表示, 最后输出res/g  和  Ann / g  (g为res与Ann 最大公因数)

    题解

    硬做会超时, 要想着归纳

    一  : 当对于一种序列, 比如2 3 5(注意5在最后面): |2 – 0| + |3 – 2| + |5 – 3| = 5; 5只出现1次, 其余2 3都出现2次,

      即: 一种序列中最后面的数出现一次, 前n-1个数出现2次

      ====> 在这所有排列中, 每个数出现总次数 =  2 * (n的阶乘) - (n-1的阶乘)

      对式子的解释: 2 * (n的阶乘): 所有数全排的种类数 * 一种排列出现两次;  (n - 1的阶乘): 当这个数在最后时, 前面的数全排

    二  : 先把绝对值拆开, 比如 |2 – 0| + |3 – 2| + |5 – 3| = 2 + 3 - 2 + 5 - 3 ,最大值5一定是正的, 3与2搭配时-->3为正; 3与5搭配时-->3为负

      即: 一个数与比它大的数搭配(挨着,不分前后)时, 它为负, 与比它小的数搭配时, 它为正

      ====> 设大于n的数有m个, 减去一个数的次数(为负的次数) = 2 * m * (n - 1的阶乘) 

      对式子的解释: 2为该数与另一个数的两种排列, m: 从m个比它大的数挑一个, 也就是Cm1 ;  (n - 1的阶乘) : 该数与另一个数绑定后全排

    重点来了, 结果快来了


    这个数最后是加减了多少倍呢?

    每个数出现的次数

    = 正的次数 - 负的次数

    = ( 出现的总次数 -  负的次数 )  -  负的次数 

    = 第一个式子 - 2 * 第二个式子

    = [2 * (n的阶乘) - (n-1的阶乘)] - [2 * ( 2 * m * (n - 1的阶乘) )]

    那结果 = [ 2 * (n的阶乘) - (n-1的阶乘) - 2 *  2 * m * (n - 1的阶乘)  ]    和    n的阶乘   ~~~(约去n-1的阶乘)~~~

    = 2 * n - 1 - 4 * m      和         n

    m = 大于该数的个数, 对数组小到大排序后(下标从0开始), 大于该数的个数 = n - i - 1, 带入上式即可

    (化简 = 2n-1-4n+4i+4 = 4i-2n+3)

    代码

    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    
    const int N = 1e5 + 10;
    
    ll res = 0, fenmu = 1;
    ll a[N];
    
    ll gcd(ll a, ll b)
    {
        return b? gcd(b, a % b): a;
    }
    int main()
    {
        int n;
        cin >> n;
        for(int i = 0; i < n; i ++)
            scanf("%lld", &a[i]);
        
        sort(a, a+n);
        for(int i = 0; i < n; i ++)
           res += (2 * n - 1 - 4 * (n - i - 1)) * a[i];
       //     res += (4i-2n+3) * a[i];
        int g = gcd(res, n);
        cout << res/g << ' '<< n/g << endl;
        return 0;
    }
  • 相关阅读:
    2019年11月4日随堂测试 最多输入字母统计
    写增删改查中间遇到的问题
    2019年12月9日下午自习成果
    2019年12月16日 分级考试
    2019年11月18日 JAVA期中考试 增删改查
    sql语言积累
    【转载】Java项目中常用的异常处理情况总结
    泛型
    C#数字格式化输出
    委托,Lambda的几种用法
  • 原文地址:https://www.cnblogs.com/la-la-wanf/p/14599118.html
Copyright © 2020-2023  润新知