zoukankan      html  css  js  c++  java
  • NOIP模拟赛-旅行者问题 解题报告

      旅行者问题

    【问题描述】

    lahub是一个旅行者的粉丝,他想成为一个真正的旅行者,所以他计划开始一段旅行。lahub想去参观n个目的地(都在一条直道上)。lahub在起点开始他的旅行。第i个目的地和起点的距离为ai千米(ai为非负整数)。不存在两个目的地和起点的距离相同。

        从第i个目的地走到第j个目的地所走的路程为 |ai-aj|千米。我们把参观n个目的地的顺序称作一次“旅行”。lahub可以参观他想要参观的任意顺序,但是每个目的地有且只能被参观一次(参观顺序为n的排列)。

        lahub把所有可能的“旅行”都写在一张纸上,并且记下每个“旅行”所要走的路程。他对所有“旅行”的路程之和的平均值感兴趣。但是他觉得计算太枯燥了,所以就向你寻求帮助。

    【输入格式】

    第一行一个正整数n。

        第二行n个非负整数a1,a2,....,an(1≤ai≤10^7)。

    【输出格式】

    两个整数,答案用最简分数形式输出,第一个为分子,第二个为分母。

    【输入样例】

    3

        2 3 5

    【输出样例】

    22 3

    【样例提示】

    样例有6种可能的旅行:

    [2, 3, 5]: 该“旅行”的路程:|2 – 0| + |3 – 2| + |5 – 3| = 5;

    [2, 5, 3]: |2 – 0| + |5 – 2| + |3 – 5| = 7;

    [3, 2, 5]: |3 – 0| + |2 – 3| + |5 – 2| = 7;

    [3, 5, 2]: |3 – 0| + |5 – 3| + |2 – 5| = 8;

    [5, 2, 3]: |5 – 0| + |2 – 5| + |3 – 2| = 9;

    [5, 3, 2]: |5 – 0| + |3 – 5| + |2 – 3| = 8. 

    答案为 1/6 * (5+7+7+8+9+8)=44/6=22/3

    【数据范围】

    30% n<=10

        50% n<=1000

    100% n<=100000

    分析:

    这道题的不免会让人想起用DFS搜下去。打出来个全排列出来。为了全排列可能还用预处理两点之间的位置。不过。做这些事情。恩。还是给WA了。

    而这道题再进一步思考呢?会让人想到。如果,只是对每条边进行一个处理呢?思考--->每条边(两个点之间的距离)对最终的答案的影响。那么如果我们走了这条边,我们接下来会有多少种路可以走呢,也就是接下来有多少种组合呢? 假设我们选择了Ai 与 Aj 这条路,接下来就会有(n-2)!种方案。那么Ai与Aj这条路就会走(n-2)!次。而这条路又有(n-1)种选择。因为我们可以选择在什么时候再走。这个时候方案数就又多了。是 (n-2)!*(n-1) ==(n-1)!。但是我们光枚举了两点之间的距离,没有枚举从起点开始的路径。而从头开始的路径的位置是固定的。假设我们从0到Ai。那么走完之后就有(n-1)!种方案。/-乘法原理-/。这样每次的情况又枚举完了。乘上权值就是我们最后的总和。



    最关键的就是我们如何去枚举整个sum(abs(A[i]-A[j]);首先,我们可以确定的是。我们就只用计算从i到j 并且 (i>j)这样计算,总路程就×2就好(走过去,走回来)。

    我们可以用递推来实现整个计算。我们可以发现一个规律:

    假设a1 > a2 > a3 > a4

    Ai为结尾的Ai-Aj的和为Si

    那么:

    S2 = a1 - a2

    S3 = a1 - a3 + a2 - a3 = (a1 - a2 + a2 - a3) + a2 - a3 = S2 + 2 *a2 - a3

    S4 = a1 - a4 + a2 - a4 + a3 - a4 = (a1 - a3 + a3 - a4) + (a2 - a3 + a3 - a4) + (a3 - a4)

    = S3 + 3 * (a3 - a4)

    我们发现这里的S是可以递推的。

    最后在计算结果的时候 分子是总和。而分母是总方案数n! 分数相约之后。分母就只剩一个n。那么我们就只需要计算gcd再同时除以gcd。

    放出代码:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int line[1000001];
    int n;
    long long int gcd(long long int a,long long int b)
    {
        return a%b==0 ? b : gcd(b,a%b);
    }
    int cmp(int a,int b)
    {
        return a>b;
    }
    int main()
    {
        freopen("tourist.in","r",stdin);
        freopen("tourist.out","w",stdout);
        long long int sum=0;
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
        {
        scanf("%d",&line[i]);
        sum+=line[i];
        }
        sort(line+1,line+1+n,cmp);
        long long int k=0,ans=0;
        for(int i=2;i<=n;++i)
        {
        k=k+(i-1)*(line[i-1]-line[i]);
        ans+=k;
        }
        sum+=ans*2;
        long long int c=gcd(sum,n);
        printf("%I64d %I64d",sum/c,n/c);
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
    
  • 相关阅读:
    623. Add One Row to Tree 将一行添加到树中
    771. Jewels and Stones 珠宝和石头
    216. Combination Sum III 组合总数三
    384. Shuffle an Array 随机播放一个数组
    382. Linked List Random Node 链接列表随机节点
    向github项目push代码后,Jenkins实现其自动构建
    centos下安装Jenkins
    python提取批量文件内的指定内容
    批处理实现:批量为文件添加注释
    python抓取每期双色球中奖号码,用于分析
  • 原文地址:https://www.cnblogs.com/uncle-lu/p/5991587.html
Copyright © 2011-2022 走看看