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 } 

未完待续。。。。。。

原文地址:https://www.cnblogs.com/dongdong222/p/10727088.html