CF#552div3題解

    第一次寫博客,有點小小的激動QAQ。表決心,談理想之類的話就很少說了,反正平時說的也夠多了。上大學以後才瞭解到算法競賽究竟是個什麼東西。高一的時候一位清華的教授還來過咱們學校普及了信息學奧賽,當時講了一道例題,上了大學以後才知道,原來,,那是漢諾塔。有點遺憾,在江蘇這樣一個試卷難考生多招生名額少的地方,信息學競賽普及度真的很低。有時候會想,若是我可以有條件在初中甚至小學就接觸編程,如今的我會不會不同。node

    上大學以後的我真的變了一我的了吧,或許是高考的失利帶給個人感觸與變化。很多人理解不了,上大學以後的我爲何拼命地學,由於他們不懂,在這裏,我終於能夠不用像之前同樣,全部的努力,全部的能力只被最後的一場考試定義。一位超級優秀的學妹曾經問過我,「學長,你有明確的目標麼」。當時,我啞口無言,才發現原來我只知道埋頭,殊不知道本身要去哪。如今,我終於明白,也終於找到了。python

    進入南理工的第一天起,我發誓我要在這裏作到最好,到目前爲止,有不少事情本身作的很不錯,但也有很多事情,本身能清楚感覺到差距的存在,就好比眼前的算法競賽。的確很多比我厲害的人是由於大學之前的基礎,但仍然有許許多多像我同樣從零開始的人啊。全部的不成功,都應該首先從自身努力程度上找緣由吧。記住,你要在這裏作到最好,那就必須讓你的努力配得上你所指望的成就。ios

 

-----------------------------------------------------------------------手動分割線,進入正題…………^.^c++

 

    前天忽然高燒,養了兩天病。原來在宿舍裏偷偷待一天這麼爽(僅此一次,下不爲例)。程序員

    錯過了昨晚的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 } 

未完待續。。。。。。

相關文章
相關標籤/搜索