• CF#552div3题解


        第一次写博客,有点小小的激动QAQ。表决心,谈理想之类的话就不多说了,反正平时说的也够多了。上大学之后才了解到算法竞赛到底是个什么东西。高一的时候一位清华的教授还来过我们学校普及了信息学奥赛,当时讲了一道例题,上了大学之后才知道,原来,,那是汉诺塔。有点遗憾,在江苏这样一个试卷难考生多招生名额少的地方,信息学竞赛普及度真的很低。有时候会想,如果我能够有条件在初中甚至小学就接触编程,现在的我会不会不一样。

        上大学之后的我真的变了一个人了吧,或许是高考的失利带给我的感触与变化。不少人理解不了,上大学之后的我为什么拼命地学,因为他们不懂,在这里,我终于可以不用像以前一样,所有的努力,所有的能力只被最后的一场考试定义。一位超级优秀的学妹曾经问过我,“学长,你有明确的目标么”。当时,我哑口无言,才发现原来我只知道埋头,却不知道自己要去哪。现在,我终于明白,也终于找到了。

        进入南理工的第一天起,我发誓我要在这里做到最好,到目前为止,有很多事情自己做的很不错,但也有不少事情,自己能清楚感受到差距的存在,就比如眼前的算法竞赛。的确不少比我厉害的人是因为大学以前的基础,但仍然有许许多多像我一样从零开始的人啊。所有的不成功,都应该首先从自身努力程度上找原因吧。记住,你要在这里做到最好,那就必须让你的努力配得上你所期望的成就。

    -----------------------------------------------------------------------手动分割线,进入正题…………^.^

        前天突然高烧,养了两天病。原来在宿舍里偷偷待一天这么爽(仅此一次,下不为例)。

        错过了昨晚的div3,今天下午汇编课上机的时间就用来写了写(每天这么多人找我DEBUG挺烦的其实。)。花了一个小时左右,过了四道题,印象中还没有比这更快过,大概是因为,这次前几题简单??粗略估计了一下罚时,如果放在昨晚的话,大概可以排到800名,错过了一次绝佳的上分机会(可惜没如果~-~)。

    A题

    C++

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define scan(i) scanf("%d",&i)
     4 int a[10];
     5 int main(){
     6     for(int i=1;i<=4;i++){
     7         scan(a[i]);
     8     }
     9     sort(a+1,a+5);
    10     for(int i=1;i<=3;i++){
    11         int x=a[4]-a[i];
    12         printf("%d ",x);
    13     }
    14     return 0;
    15 }

       我还是个病人,先睡觉了。明天再来哈。

    Python

    1 a, b, c, d = sorted(map(int, input().split()))
    2 print(d-a, d-b, d-c)

    只要两行,有点气人唉

    B题

     

       这道题也很简单,只要细心一点把所有情况考虑全就可以了。对于一组数,可以对每一个数进行三种操作,加一个D,减一个D,或者不变。注意,对于这一组数,正数D的值是固定的。那么首先需要考虑的是这一组数是由多少个不同的值组成,可以用一下unique函数,(!!!用之前一定要先排序!!上次因为这个问题卡了好久)。如果组成这一组数的值超过三个,那么一定不存在D满足条件。如果正好是三个,则判断是否成等差数列。

        而对于一个或两个的情况,D一定存在,此时需要找一个最小的D。如果是一个,那么D显然是0。而,如果是两个的话,则要分情况,如果两数之差为偶数,则输出差的一半。而如果两数之差为奇数,则只能将其中一个变为另外一个,输出两数之差。

      C++

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int a[105];
     4 #define scan(i) scanf("%d",&i)
     5 int main(){
     6     int n;scan(n);
     7     for(int i=1;i<=n;i++)scan(a[i]);
     8     sort(a+1,a+n+1);
     9     int x=unique(a+1,a+n+1)-(a+1);
    10     if(x>=4)cout<<-1;
    11     else if(x==3){
    12         if((a[2]-a[1])==(a[3]-a[2]))cout<<(a[2]-a[1]);
    13         else cout<<-1;
    14     }
    15     else if(x==2){
    16         if((a[2]+a[1])%2==0)cout<<(a[2]+a[1])/2-a[1];
    17         else cout<<(a[2]-a[1]);
    18     }
    19     else cout<<0;
    20     return 0;
    21 } 

      Python

     1 input()
     2 a = list(set(list(map(int, input().split()))))
     3 a = sorted(a)
     4 if len(a) == 1:print(0)
     5 elif len(a) == 2:
     6     x = a[1]-a[0]
     7     if x % 2 == 0:
     8         x = x/2
     9         print(int(x))
    10     else:print(x)
    11 elif len(a)==3:
    12     x = a[1] - a[0]
    13     if a[2] - a[1] == x:
    14         print(x)
    15     else:print(-1)
    16 else:print(-1)

    python只要先把列表转换为集合,再把集合转换为列表,一条语句就很方便的完成了去重的过程。不过python真心慢啊,时长用了c++的四倍。

     C题

    没错,又是一道模拟题,我这种菜鸡也就只能写写这种模拟题了。首先算一下所有食物至多能够坚持多少个星期,然后再对从周一到周日出发七种情况进行模拟,得出最长天数就好了

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int a,b,c;
     4 char w[8]={'.','a','b','c','a','c','b','a'};
     5 int getday(int d){                        #d为1到7,分别表示周一到周日                    
     6     int a1=a,b1=b,c1=c;                    #存储去除整周之后剩余的食物 
     7     int cnt=0;
     8     while(1){
     9         if(w[d]=='a'){
    10             if(a1==0)break;
    11             else{
    12                 a1--;cnt++;
    13             }
    14         }
    15         else if(w[d]=='b'){
    16             if(b1==0)break;
    17             else{
    18                 b1--;cnt++;
    19             }
    20         }
    21         else{
    22             if(c1==0)break;
    23             else{
    24                 c1--;cnt++;
    25             }
    26         }
    27         if(d==7)d=1;                    #表示已经到周日了,下一天应该是周一 
    28         else d++;
    29     }
    30     return cnt;
    31 }
    32 int main(){
    33     scanf("%d%d%d",&a,&b,&c);
    34     int i1=a/3,i2=b/2,i3=c/2;
    35     int i=min(i1,i2);i=min(i,i3);
    36     long long day=7*i;
    37     a-=3*i;b-=2*i;c-=2*i;
    38     int ma=0;
    39     for(int i=1;i<=7;i++){
    40         if(getday(i)>ma)ma=getday(i);
    41     }
    42     day+=ma;
    43     printf("%lld",day);
    44     return 0;
    45 }

       老师说一个厉害的程序员,main函数应该是相当整洁的。像这种对不同情况模拟取最优值的情况,尽量的用函数去写吧。

    D题

     

    这道题是一条普通的的贪心。只要想清楚一个问题就好了,在有阳光照射的地方,如果用电池,电池减一但收集器加一,也就是没有损耗,但如果用收集器,总能量就减一,为了尽量跑的远,就需要尽可能的在有阳光的地方用电池,这样一来,在没有阳光的地方,就需要尽可能的不用电池。注意,收集器有最大容量。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=2e5+5;
     4 int m[maxn];
     5 int n,b,a;
     6 int flag=1;
     7 #define scan(i) scanf("%d",&i)
     8 int main(){
     9     scan(n);scan(b);scan(a);
    10     for(int i=1;i<=n;i++)scan(m[i]);
    11     int i;int a1=a;
    12     for(i=1;i<=n;i++){
    13         if(a1==0&&b==0){
    14             flag=0;
    15             cout<<(i-1);break;
    16         }
    17         if(m[i]==1){
    18             if(b&&a1<a){
    19                 b--;a1++;
    20             }
    21             else{
    22                 a1--;
    23             }
    24         }
    25         else{
    26             if(a1)a1--;
    27             else b--;
    28         }
    29         if(a1==0&&b==0){
    30             flag=0;
    31             cout<<i;break;
    32         }
    33     }
    34     if(flag)cout<<n;     #wa了一次,就是因为没有这条语句。忘记了走完全部路程之后的输出。
    35     return 0;
    36 } 

    看到这题,想起来上学期期末那段时间写的一道dp,也是一个路程中能量补给的问题。(话说那段时间是真轻松,整个一月几乎没课,期末考又没压力,偷偷带了电脑写代码^-^)

    龟兔赛跑

    Time Limit: 1000/1000 MS (Java/Others)

    Memory Limit: 32768/32768 K (Java/Others)

    Description
    据说在很久很久以前,可怜的兔子经历了人生中最大的打击——赛跑输给乌龟后,心中郁闷,发誓要报仇雪恨,于是躲进了杭州下沙某农业园卧薪尝胆潜心修炼,
    终于练成了绝技,能够毫不休息得以恒定的速度(VR m/s)一直跑。兔子一直想找机会好好得教训一下乌龟,以雪前耻。
    最近正值HDU举办50周年校庆,社会各大名流齐聚下沙,兔子也趁此机会向乌龟发起挑战。虽然乌龟深知获胜希望不大,不过迫于舆论压力,只能接受挑战。
    比赛是设在一条笔直的道路上,长度为L米,规则很简单,谁先到达终点谁就算获胜。
    无奈乌龟自从上次获胜以后,成了名龟,被一些八卦杂志称为“动物界的刘翔”,广告不断,手头也有了不少积蓄。为了能够再赢兔子,乌龟不惜花下血本买了最先
    进的武器——“"小飞鸽"牌电动车。这辆车在有电的情况下能够以VT1 m/s的速度“飞驰”,可惜电池容量有限,每次充满电最多只能行驶C米的距离,以后就只能用脚
    来蹬了,乌龟用脚蹬时的速度为VT2 m/s。更过分的是,乌龟竟然在跑道上修建了很多很多(N个)的供电站,供自己给电动车充电。其中,每次充电需要花费T秒钟
    的时间。当然,乌龟经过一个充电站的时候可以选择去或不去充电。
    比赛马上开始了,兔子和带着充满电的电动车的乌龟并列站在起跑线上。你的任务就是写个程序,判断乌龟用最佳的方案进军时,能不能赢了一直以恒定速度奔跑
    的兔子。

    Input

    本题目包含多组测试,请处理到文件结束。每个测试包括四行:
    第一行是一个整数L代表跑道的总长度
    第二行包含三个整数N,C,T,分别表示充电站的个数,电动车冲满电以后能行驶的距离以及每次充电所需要的时间
    第三行也是三个整数VR,VT1,VT2,分别表示兔子跑步的速度,乌龟开电动车的速度,乌龟脚蹬电动车的速度
    第四行包含了N(N<=100)个整数p1,p2...pn,分别表示各个充电站离跑道起点的距离,其中0<p1<p2<...<pn<L
    其中每个数都在32位整型范围之内。

    Output

    当乌龟有可能赢的时候输出一行 “What a pity rabbit!"。否则输出一行"Good job,rabbit!";
    题目数据保证不会出现乌龟和兔子同时到达的情况。

    Sample Input

    100 3 20 5 5 8 2 10 40 60 100 3 60 5 5 8 2 10 40 60

    Sample Output

    Good job,rabbit! What a pity rabbit!

          这道题,当时想了好久。这是我第一次知道动态规划这个东西。自己写的时候,就当做贪心来处理,果不其然的wa了,还满以为自己想的没错,我在每走一步之前都选择的是到下一步时间最短的方法,

    最后的总时长理应也是最短的呀。好吧,当时的想法真愚蠢。贪心算法大概,就是“鼠目寸光”吧,只想着眼前的利益,却忘了要得到的是什么,而用动态规划的话,大概就是“运筹帷幄,决胜千里”的感觉

    吧,只要保证最后结果最优化。中间的某一些点之间或许没有贪心得到的效果好,但这一点小牺牲是为了换取更大的利益。运筹学真的是一门很深的学问,有机会一定要好好钻研。

      状态转移方程很简单  dp[i]=min(dp[i],dp[j]+time)  j<i     其余的一些附加条件计算稍微繁琐一点,小心写就好了。

     1 #include <iostream>
     2 using namespace std;
     3 int path[102];
     4 double dp[102];
     5 int main() {
     6     int L, N, C, T, vr, vt1, vt2;    
     7     while (cin >> L) {
     8     cin >> N >> C >> T;
     9     cin >> vr >> vt1 >> vt2;
    10     for (int i = 1; i <= N; ++i)
    11         cin >> path[i];
    12     path[0] = 0; path[N + 1] = L;
    13     dp[0] = 0;
    14     for(int i=1;i<=N+1;i++){
    15         double min=1000000;      
    16         for(int j=0;j<i;++j){
    17             double temp;
    18             if(path[i]-path[j]>=C)
    19                 temp = dp[j] + C * 1.0 / vt1 + (path[i] - path[j] - C)*1.0 / vt2;
    20             else
    21                 temp=dp[j]+(path[i]-path[j])*1.0/vt1;
    22             if(j>0)                    
    23                 temp+=T;
    24             if(temp<min)                   
    25                 min=temp;
    26         }
    27         dp[i] = min;
    28     }
    29     double rt; 
    30     rt = L * 1.0 / vr;
    31     if(dp[N+1]<rt)
    32         cout<<"What a pity rabbit!"<<endl; 
    33     else 
    34         cout<<"Good job,rabbit!"<<endl;   
    35     }
    36     return 0;
    37 }

    E题

    还是模拟。。。。。终于用了一回上学期学过的手写链表,虽然会有一点麻烦,皮一下依然很开心。这题主要要说的,就是如何快速,找到当前情况下存在的最大值,和最大值对应的下标。

    用一个check数组保存每一个值的状态,这样在寻找最大值的时候,可以从n开始,如果这个值已经被用过了,就减一再判断,直到找到当前未用的最大值。然后用position数组保存每一个值的下标,方便索引。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=2e5+5;
     4 int n,k,x;
     5 struct node{
     6     int val;
     7     int id;
     8     node *pre;
     9     node *next;
    10 };
    11 node p[maxn];
    12 int ans[maxn];
    13 int position[maxn];          
    14 bool check[maxn];            
    15 inline void build(){
    16     for(int i=1;i<=n;i++){
    17         scanf("%d",&x);
    18         p[i].val=x;
    19         p[i].id=i;
    20         p[i].pre=&p[i-1];p[i].next=&p[i+1];
    21         if(i==1)p[i].pre=NULL;
    22         if(i==n)p[i].next=NULL;
    23         position[x]=i;
    24     }
    25     return;
    26 }
    27 int main(){
    28     scanf("%d%d",&n,&k);
    29     build();
    30     int ma=n;
    31     int an=1;
    32     while(ma!=0){
    33         check[ma]=true;
    34         ans[position[ma]]=an;
    35         int po=position[ma];
    36         int k1=k;int k2=k;
    37         int p1=po,p2=po;
    38         while(k1--){
    39             if(p[po].next==NULL)break;
    40             int v=p[po].next->val; 
    41             check[v]=true;
    42             ans[position[v]]=an;
    43             p1=p[po].next->id;
    44             p[po].next=p[po].next->next;
    45         }
    46         while(k2--){
    47             if(p[po].pre==NULL)break;
    48             int v=p[po].pre->val; 
    49             check[v]=true;
    50             ans[position[v]]=an;
    51             p2=p[po].pre->id;
    52             p[po].pre=p[po].pre->pre;    
    53         }
    54         if(p[p1].next!=NULL)p1=p[p1].next->id;
    55         else p1=n+1;
    56         if(p[p2].pre!=NULL)p2=p[p2].pre->id;
    57         else p2=0;
    58         if(p1<=n&&p2>=1){
    59             p[p1].pre=&p[p2];
    60             p[p2].next=&p[p1];
    61         }
    62         if(p1<=n&&p2<1)p[p1].pre=NULL;
    63         if(p1>n&&p2>=1)p[p2].next=NULL;
    64         if(an==1)an=2;else an=1;
    65         while(check[ma])ma--;
    66     }
    67     for(int i=1;i<=n;i++)
    68         printf("%d",ans[i]);
    69     return 0;
    70 } 

    未完待续。。。。。。

  • 相关阅读:
    sql学习2----函数
    网络相关命令
    网络相关概念
    linux学习(2)--指令
    linux学习(1)--基本知识
    Linux学习技巧
    VMware安装Linux
    接口测试
    app测试--DDMS的使用
    app测试--性能测试DDMS
  • 原文地址:https://www.cnblogs.com/dongdong222/p/10727088.html
Copyright © 2020-2023  润新知