• 2020年百度之星程序设计大赛-初赛二


    2020年百度之星程序设计大赛-初赛二前两题解答代码思路
    Poker

    Problem Description
    小沃沃在玩一个有趣的游戏。
    初始他有 n 块钱,每一轮他需要投入至少 m 块钱,系统会拿走其中 p% 的钱,并把剩下的钱还给他。
    请问在最优情况下,小沃沃最多可以玩多少轮?
    假设当前一轮小沃沃投入了 x 块钱,那么他可以收回 ⌊x*(1−p%)⌋ 块钱,其中⌊a⌋ 表示 a 取下整。 小沃沃每一轮投入的钱不能超过他现在拥有的钱。
    每一轮投入的钱必须为整数。

    Input
    第一行一个正整数 test(1≤test≤100000) 表示数据组数。
    对于每组数据,一行三个整数 n,m,p(1≤n≤100000,1≤m≤1000,1≤p≤100)。
    Output
    对每组数据输出一行一个整数表示答案。

    Sample Input

    2

    10 50

    10 100

    Sample Output

    9

    5

    这道题比较简单,第一次提交遇到超时问题,后来使用了scanf和printf解决问题。

    Accept代码:

    #include<bits/stdc++.h>
    using namespace std;
    int main()
    {
        int test,n,m,sum;
        float p;
        cin>>test;
        while(test--)
        {
            
            scanf("%d%d%f",&n,&m,&p);//cin和cout会超时 
            int r=n,nums=0;
            while(r>=m)
            { 
                nums++;
                r=r-m*p*0.01;
            }
            printf("%d
    ",nums); 
        }
        return 0;
    } 

    目前官方提示: 观察到小沃沃每次只会投入 m 块钱,当他手上的钱大于等于 m 时,他可以继续玩,每次会被拿走⌈m∗p%⌉ 这么多钱。那么就很好算了。

    Distance

    Problem Description
    小沃沃所在的世界是一个二维平面。他有 nn 个朋友,第 ii 个朋友距离他的距离为 a[i],小沃沃并不知道这些朋友具体在什么点上。
    请问在最优情况下,小沃沃的朋友两两之间的欧几里得距离的和的最小值是几?
    假设小沃沃的位置为 P_0 = (x_0,y_0),第 i 个朋友的位置为 P_i = (x_i,y_i),对于所有的 i,需要满足 dist(P_0, P_i) = a[i],并且∑ i=1 n−1∑ j=i+1 n dist(Pi,Pj) 最小,其中 dist(X,Y)dist(X,Y) 为连接点 XX 和点 YY 的线段的长度。x_i,y_i都可以是任意实数。

    Input
    第一行一个正整数 test(1≤test≤10) 表示数据组数。
    对于每组数据,第一行一个正整数 n(1≤n≤100000)。
    接下来一行 n 个整数,第 i 个整数 a[i] (1≤a[i]≤1000000000) 表示第 i 个朋友和小沃沃的距离。
    Output
    对每组数据输出一行一个数,表示∑ i=1 n−1∑ j=i+1 ndist(Pi,P j) 的最小值。答案需要四舍五入到整数。

    Sample Input
    2
    2
    3 5
    5
    1 2 3 4 5
    Sample Output
    2
    20

    这道题目也好理解,写程序思路直接,只是又遇到了超时问题。

    #include<bits/stdc++.h>
    #include<cstdlib>
    using namespace std;
    //int a[1000000005];//数组太大,会出错 
    int *a = new int[1000000005];//全局变量动态分配 
    int main()
    {
        int test,n,i,j;
        scanf("%d",&test);
        while(test--)
        {    
            scanf("%d",&n);
            for(i=1;i<=n;i++)
                scanf("%d",&a[i]);
            int sum=0;
            sort(a+1,a+n+1);//排序
            i=1;
            while(i<=n-1)
    //        for(i=1;i<=n-1;i++)//时间复杂度O(n^2),超时
            {
                j=i+1;
                for(j=i+1;j<=n;j++)
                {
                    sum=sum+a[j]-a[i];
                }
                i++;
            }
            printf("%d
    ",sum);
        }
        delete a;
        return 0;
    }

    这道题目出现超时问题,可能数组很大或者算法不够好,两个for循环时间复杂度较高O(n^2),虽然本地测试的时间限时小于1000ms,但是提交还是超时了,后续需要看看其他大佬怎么做的……

    目前官方提示:最优情况下,所有人必然在由小沃沃出发的在一条射线上(任意两个人的距离都最小)。我们把 a 排序以后,算距离和就比较简单了。

    测试时间:

     


     我来更新Distance题目啦,这个解法就Accept了,转化思路,可以通过数学推导就计算最小的距离,最终时间复杂度为O(n)。
    Accept代码:

    #include<bits/stdc++.h>
    typedef long long LL;
    using namespace std;
    
    int main()
    {
        int test,n,i,j;
        ios::sync_with_stdio(false);//避免超时
        cin.tie(0);
        cout.tie(0);
        cin>>test;
        while(test--)
        {
            cin>>n;
            vector<LL> a(n);
            for(i=0;i<n;i++)
                cin>>a[i];
            LL sum=0;
            sort(a.begin(),a.end());
            for(i=0;i<n-1;i++)
            {
                //可通过数学推导得出,实现O(n)的时间复杂度 
                sum += (a[i+1] - a[i]) * (LL)(i + 1) * (LL)(n - i - 1);
            }
            cout<<sum<<'
    ';
        }
        return 0;
    }

    sum += (a[i+1] - a[i]) * (i + 1) * (n - i - 1)
    关键的这一步数学推导可能有许多朋友存在疑问,为什么能用此取而代之2个for循环呢?
    我的推导思路是这样的:
    根据题目我们假设更普遍的数据为a[4]={3,5,8,11},我们容易发现在2次循环做法时候,是存在许多重复计算的。
    比如:计算3与8的距离,我们用到了3与5、5与8的距离,即是a[2]-a[0]=8-3=2+3, a[1]-a[0]=5-3=2。以此类推。

    dist(3,8)dist(3,5)dist(5,8)
    a[2]-a[0]=8-3=2+3 a[1]-a[0]=5-3=2 a[2]-a[1]=8-5=3

    我们似乎发现了规律,这种做法类似于动态规划,避免了重叠子问题的计算导致效率降低,所以针对这道题可以采用只计算每一个子问题一次,再记录每个子问题被计算的次数,进而提高效率,降低时间复杂度。

    (a[i+1] - a[i]) * (i + 1) * (n - i - 1)
    分析:
    1、a[i+1] - a[i] 就是相邻2个元素的距离,这个好理解。
    2、i+1 就是 a[i+1] 元素之前需要用到a[i+1] - a[i]距离计算的次数。
    3、n -i -1 就是 a[i] 元素之后需要用到a[i+1] - a[i]距离计算的次数。
    举例
    a[4]={3,5,8,11}
    根据推导式子为:
    第一轮:2 * 1 * 3 = 6
    第二轮:3 * 2 * 2 = 12
    第三轮:3 * 3 * 1 = 9
    计算结果27,与我们自行计算一致。实现O(N)时间复杂度。

    ————————————————
    版权声明:本文为CSDN博主「Charzous」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/Charzous/article/details/107581452

     我的CSDN博客:https://blog.csdn.net/Charzous/article/details/107581452

     我的博客园:https://www.cnblogs.com/chenzhenhong/p/13377665.html
    ————————————————
    版权声明:本文为CSDN博主「Charzous」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/Charzous/article/details/107581452

  • 相关阅读:
    ASP.NET MVC Core的ViewComponent
    docker学习笔记
    C#调用RabbitMQ实现消息队列(转)
    在Gerrit中修改project.config
    Linux设备模型:6、Bus
    Linux设备模型:5、device和device driver
    Linux设备模型:4、sysfs
    Linux设备模型:3、Uevent
    Linux设备模型:2、基本对象 Kobject、Kset、Ktype
    Linux设备模型:1、设计思想
  • 原文地址:https://www.cnblogs.com/chenzhenhong/p/13377665.html
Copyright © 2020-2023  润新知