SHU 2013 暑期集訓(7-14)解題報告

Problem A: 神奇的fans

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 84   Solved: 30
[ Submit][ Status][ Web Board]

Description

傳說fans是一個數學天才。在他五歲那年,從一堆數字卡片中選出了4張 卡片:5,7,6,8。這4個數字有什麼神祕之處呢?若是把這4張卡片自左往右的排成:5,6,7,8。你就會發現:原來這4個數字構成了等差數列!當年 fans選出了n組卡片,聽說都可以構成等差數列。可是事實真的是這樣嗎?fans真的有這麼神奇嗎? n組數據就是fans選出的n組卡片,請你判斷每一組卡片是否能構成等差數列.php

Input

第一個數爲數據的組數n,表示後面有n行,每行中的第一個數爲該組數據的元素個數m(1≤m≤100),其後是m個正整數(不會超出int的表示範圍)。html

Output

若是可以構成等差數列,輸出「yes」,不然輸出「no」。ios

Sample Input

2
4 5 7 6 8
8 1 7 3 2 8 12 78 3

Sample Output

yes
no
題目大意:給你n個數,問是否能夠構成等差數列
分析:水題,sort後判斷一下是否是等差便可
 1 #include <iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 int n,t;
 6 int a[110];
 7 int main()
 8 {
 9     scanf("%d", &t);
10     while(t--)
11     {
12         scanf("%d", &n);
13         for (int i=0; i<n; i++)
14             scanf("%d",&a[i]);
15         sort(a,a+n);
16         if (n<=2)
17         {
18             printf("yes\n");
19             continue;
20         }
21         int flag=1;
22         for(int i=1; i<n-1; i++)
23         {
24             if((a[i+1]-a[i])!=(a[1]-a[0]))
25             {
26                 flag=0;
27                 break;
28             }
29         }
30         if (flag)
31             printf("yes\n");
32         else
33             printf("no\n");
34     }
35     return 0;
36 }
View Code

Problem B: 伊甸園日曆遊戲

Time Limit: 2 Sec   Memory Limit: 128 MB
Submit: 18   Solved: 5
[ Submit][ Status][ Web Board]

Description

      Adam和Eve玩一個遊戲,他們先從1900.1.1到2001.11.4這個日期之間隨意抽取一個日期出來。而後他們輪流對這個日期進行操做:       1  :  把日期的天數加1,例如1900.1.1變到1900.1.2       2  :  把月份加1,例如:1900.1.1變到1900.2.1       其中若是天數超過應有天數則日期變動到下個月的第1天。月份超過12則變到下一年的1月。並且進行操做二的時候,若是有這樣的日期:1900.1.31,則變成了1900.2.31,這樣的操做是非法的,咱們不容許這樣作。並且全部的操做均要考慮曆法和閏年的規定。       誰先將日期變到2001.11.4誰就贏了。       每次遊戲都是Adam先操做,問他有沒有必勝策略?

Input

    一個測試點。多組數據。     第一行爲數據組數。     接下來一行X  Y  Z表示X年Y月Z日

Output

    輸出「YES」or「NO」表示亞當是否有必勝策略。 

Sample Input

3
2001 11 3
2001 11 2
2001 10 3

Sample Output

YES
NO
NO

HINT

    建議先把全部狀況都算出來^_^數組

題目大意:給你一個時間(年月日),你能夠將月份+1或將日+1,誰先達到2001.11.4誰贏了,若是你先操做,問你是否必贏。ide

分析:博弈論,找規律。打表找到的規律是若是(月份+日)爲偶數則必定贏,不然輸,但有兩組特殊數據即11月30與9月30,這兩組也爲贏。函數

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 int t,y,m,d;
 6 int main ()
 7 {
 8     scanf("%d",&t);
 9     while(t--)
10     {
11         scanf("%d%d%d",&y,&m,&d);
12         if (m==9&&d==30)
13             printf("YES\n");
14         else if(m==11&&d==30)
15             printf("YES\n");
16         else if((m+d)&1)
17             printf("NO\n");
18         else
19             printf("YES\n");
20     }
21 }
View Code

Problem C:  核電站問題

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 76   Solved: 13
[ Submit][ Status][ Web Board]

Description

        一個核電站有N個放核物質的坑,坑排列在一條直線上。若是連續M個坑中放入核物質,則會發生爆炸,因而,在某些坑中可能不放核物質。         如今,請你計算:對於給定的N和M,求不發生爆炸的放置核物質的方案總數。

Input

輸入文件只有一行,兩個正整數N,M。

Output

輸出文件只有一個正整數,表示方案總數。

Sample Input

4 3

Sample Output

13

HINT

所有數據n< =50,m< =5測試

題目大意:上面說的很清楚了spa

分析:遞推,找規律。令f[i]表示i個電站的方案數,那麼f[i]=2*f[i-1]-f[i-m-1].net

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 long long  s[60];
 6 int main ()
 7 {
 8     int n,m;
 9     while(scanf("%d%d",&n,&m)!=EOF)
10     {
11         s[4]=s[5]=1;
12         for(int i=6; i<=n+6; ++i)
13         {
14             s[i]=2*s[i-1]-s[i-m-1];
15         }
16         printf("%lld\n",s[n+5]);
17     }
18 }
View Code

Problem D: Function(Function(F...

Time Limit: 2 Sec   Memory Limit: 128 MB
Submit: 58   Solved: 13
[ Submit][ Status][ Web Board]

Description

對於一個遞歸函數w(a,b,c) 若是a< =0  or  b< =0  or  c< =0就返回值1. 若是a> 20  or  b> 20  or  c> 20就返回w(20,20,20) 若是a< b而且b< c  就返回w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c) 其它別的狀況就返回w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1) 這是個簡單的遞歸函數,但實現起來可能會有些問題。當a,b,c均爲15時,調用的次數將很是的多。你要想個辦法才行.

Input

會有若干行. 並以-1,-1,-1結束.

Output

輸出若干行

Sample Input

1 1 1
2 2 2
-1 -1 -1

Sample Output

w(1, 1, 1) = 2
w(2, 2, 2) = 4
題目大意:給了你一個遞歸式,要求你求答案。
分析:記憶化搜索或遞推。
一、若是直接寫成遞歸形式會超時(這是必定的),因此採用數組保存每一次搜索到的數據,下次再搜索到這個位置時就直接返回不在遞歸下去。
二、直接寫成遞推形式,二者沒什麼太大區別。
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #define maxlen 30
 5 using  namespace std;
 6 int f[maxlen][maxlen][maxlen];
 7 int main()
 8 {
 9     int  a,b,c;
10     for (int i=0; i<=20; i++)
11     {
12         for (int j=0; j<=20; j++)
13         {
14             for (int k=0; k<=20; k++)
15             {
16                 if ((i==0)||(j==0)||(k==0)) f[i][j][k]=1;
17                 else if ((i<j)&&(j<k)) f[i][j][k]=f[i][j][k-1]+f[i][j-1][k-1]-f[i][j-1][k];
18                 else f[i][j][k]=f[i-1][j][k]+f[i-1][j-1][k]+f[i-1][j][k-1]-f[i-1][j-1][k-1];
19             }
20         }
21     }
22     while (scanf("%d%d%d",&a,&b,&c))
23     {
24         if(a==-1&&b==-1&&c==-1)
25             break;
26         if ((a<=0)||(b<=0)||(c<=0))
27             printf("w(%d, %d, %d) = 1\n",a,b,c);
28         else if ((a>20)||(b>20)||(c>20))
29             printf("w(%d, %d, %d) = %d\n",a,b,c,f[20][20][20]);
30         else
31             printf("w(%d, %d, %d) = %d\n",a,b,c,f[a][b][c]);
32     }
33     return (0);
34 }
View Code

Problem E: 火車票

Time Limit: 2 Sec   Memory Limit: 128 MB
Submit: 8   Solved: 7
[ Submit][ Status][ Web Board]

Description

一個鐵路線上有n(2< =n< =10000)個火車站,每一個火車站到該線路的首發火車站距離都是已知的。任意兩站之間的票價以下表所示: 站之間的距離X 票價 0< X< =L1 C1  L1< X< =L2 C2 L2< X< =L3 C3 其中L1,L2,L3,C1,C2,C3都是已知的正整數,且(1  < =  L1  <   L2  <   L3  < =  10^9,  1  < =  C1  <   C2  <   C3  < =  10^9)。顯然若兩站之間的距離大於L3,那麼從一站到另外一站至少要買兩張票。注意:每一張票在使用時只能從一站開始到另外一站結束。 如今須要你對於給定的線路,求出從該線路上的站A到站B的最少票價。你能作到嗎?

Input

輸入文件的第一行爲6個整數,  L1,  L2,  L3,  C1,  C2,  C3  (1  < =  L1  <   L2  <   L3  < =  10^9,  1  < =  C1  <   C2  <   C3  < =  10^9)  ,這些整數由空格隔開.第二行爲火車站的數量N  (2  < =  N  < =  10000).第三行爲兩個不一樣的整數A、B,由空格隔開。接下來的  N-1  行包含從第一站到其餘站之間的距離.這些距離按照增加的順序被設置爲不一樣的正整數。相鄰兩站之間的距離不超過L3.  兩個給定火車站之間行程花費的最小值不超過10^9,並且任意兩站之間距離不超過  10^9。

Output

輸出文件中只有一個數字,表示從A到B要花費的最小值. 

Sample Input

3 6 8 20 30 40
7
2 6
3
7
8
13
15
23

Sample Output

70

HINT

題目大意:給你三種距離對應的票價,而後給你n個站之間的距離,問你從站a->站b最少的費用是多少。code

分析:動態規劃。令dp[i]表示第a個站到第i個站的最小費用,那麼有三種狀況,即分別買三種車票(若是能夠)。。。

因此狀態轉移方程爲dp[i]=min{dp[j]+c1,dp[k]+c2,dp[l]+c3},j,k,l分別表示買相應車票可以到的最遠的車站編號。

這個程序有點小問題,TLE,可是卻過了。爲何能過呢?稍後解答

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 #define maxlen 10010
 6 #define INF 0x3fffffff
 7 using  namespace std;
 8 long long   dp[maxlen],dist[maxlen];
 9 int l1,l2,l3,c1,c2,c3;
10 int n,a,b;
11 int main ()
12 {
13     while(scanf("%d%d%d%d%d%d",&l1,&l2,&l3,&c1,&c2,&c3)!=EOF)
14     {
15         scanf("%d",&n);
16         scanf("%d%d",&a,&b);
17         dist[1]=0;
18         for(int i=2;i<=n;++i)
19             scanf("%lld",&dist[i]);
20         for(int i=0;i<=n;++i)
21             dp[i]=INF;
22         dp[a]=0;
23         for(int i=a;i<=b;++i)
24         {
25             for(int j=a;j<=b;++j)
26             {
27                 if(abs(dist[i]-dist[j])<=l1)
28                     dp[i]=min(dp[i],dp[j]+c1);
29                 else if(abs(dist[i]-dist[j]<=l2))
30                     dp[i]=min(dp[i],dp[j]+c2);
31                 else  if(abs(dist[i]-dist[j]<=l3))
32                     dp[i]=min(dp[i],dp[j]+c3);
33             }
34         }
35         printf("%lld\n",dp[b]);
36     }
37 }
View Code

爲何上面錯誤的代碼能過呢?由於測試數據只有一組!!!就只有樣例,因此下面的神級代碼也能夠過。=。=明天加數據rejudge吧。

1 #include <iostream>
2 #include <cstdio>
3 using  namespace std;
4 int main ()
5 {
6     printf("70\n");
7 }
神級代碼

Problem F: 搭建雙塔

Time Limit: 2 Sec   Memory Limit: 128 MB
Submit: 15   Solved: 8
[ Submit][ Status][ Web Board]

Description

        2001年9月11日,一場突發的災難將紐約世界貿易中心大廈夷爲平地,Mr.  F曾親眼目擊了此次災難。爲了記念「9?11」事件,Mr.  F決定本身用水晶來搭建一座雙塔。         Mr.  F有N塊水晶,每塊水晶有一個高度,他想用這N塊水晶搭建兩座有一樣高度的塔,使他們成爲一座雙塔,Mr.  F能夠從這N塊水晶中任取M(1≤M≤N)塊來搭建。可是他不知道可否使兩座塔有一樣的高度,也不知道若是能搭建成一座雙塔,這座雙塔的最大高度是多少。因此他來請你幫忙。         給定水晶的數量N(1≤N≤100)和每塊水晶的高度Hi(N塊水晶高度的總和不超過2000),你的任務是判斷Mr.  F可否用這些水晶搭建成一座雙塔(兩座塔有一樣的高度),若是能,則輸出所能搭建的雙塔的最大高度,不然輸出「Impossible」。

Input

        輸入的第一行爲一個數N,表示水晶的數量。第二行爲N個數,第i個數表示第i個水晶的高度。

Output

        輸出僅包含一行,若是能搭成一座雙塔,則輸出雙塔的最大高度,不然輸出一個字符串「Impossible」。

Sample Input

5
1 3 4 5 2

Sample Output

7

HINT

題目大意:給你n個數的水晶序列,問你能不能將這些水晶構成兩個高度相同的塔,若是能夠輸出最大的塔高。

分析:動態規劃,dp[i][j]表示第一座塔高i,第二座高j能不能達到,(1爲能夠,0爲不能夠)

那麼就是變形0-1揹包了,一個水晶能夠加入第一座塔,也能夠加入第二座,或者不加。枚舉每一個水晶,記錄每次可能的狀況,最後搜索最大的i使dp[i][i]=1就是答案,若是沒有則輸出Impossible。

注意點:初始化爲dp[0][0]=1,其他爲0,但最後若是有(0,0)的應該是輸出Impossible的。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 #define maxlen 2100
 6 #define INF 0x7fffff
 7 using  namespace std;
 8 bool dp[maxlen][maxlen];
 9 int num[200];
10 int n;
11 int main()
12 {
13     while(scanf("%d",&n)!=EOF)
14     {
15         memset(dp,0,sizeof(dp));
16         for(int i=0; i<n; ++i)
17             scanf("%d",&num[i]);
18         dp[0][0]=true;
19         for(int i=0; i<n; ++i)
20         {
21             for(int j=1010; j>=0; --j)
22             {
23                 for(int k=1010; k>=0; --k)
24                 {
25                     if(dp[j][k]==true)
26                     {
27                         if(j+num[i]<=1010)
28                             dp[j+num[i]][k]=true;
29                         if (k+num[i]<=1010)
30                             dp[j][k+num[i]]=true;
31                     }
32                 }
33             }
34         }
35         int flag=0;
36         for(int i=1010; i>0; --i)
37         {
38             if(dp[i][i]==true)
39             {
40                 flag=1;
41                 printf("%d\n",i);
42                 break;
43             }
44         }
45         if(!flag)
46             printf("Impossible\n");
47     }
48 }
View Code

Problem G: 過河

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 10   Solved: 2
[ Submit][ Status][ Web Board]

Description

        在河上有一座獨木橋,一隻青蛙想沿着獨木橋從河的一側跳到另外一側。在橋上有一些石子,青蛙很討厭踩在這些石子上。因爲橋的長度和青蛙一次跳過的距離都是正整數,咱們能夠把獨木橋上青蛙可能到達的點當作數軸上的一串整點:0,1,……,L(其中L是橋的長度)。座標爲0的點表示橋的起點,座標爲L的點表示橋的終點。青蛙從橋的起點開始,不停的向終點方向跳躍。一次跳躍的距離是S到T之間的任意正整數(包括S,T)。當青蛙跳到或跳過座標爲L的點時,就算青蛙已經跳出了獨木橋。         題目給出獨木橋的長度L,青蛙跳躍的距離範圍S,T,橋上石子的位置。你的任務是肯定青蛙要想過河,最少須要踩到的石子數。         對於30%的數據,L  < =  10000;         對於所有的數據,L  < =  10^9。

Input

        輸入的第一行有一個正整數L(1  < =  L  < =  10^9),表示獨木橋的長度。第二行有三個正整數S,T,M,分別表示青蛙一次跳躍的最小距離,最大距離,及橋上石子的個數,其中1  < =  S  < =  T  < =  10,1  < =  M  < =  100。第三行有M個不一樣的正整數分別表示這M個石子在數軸上的位置(數據保證橋的起點和終點處沒有石子)。全部相鄰的整數之間用一個空格隔開。

Output

        輸出只包括一個整數,表示青蛙過河最少須要踩到的石子數。

Sample Input

10
2 3 5
2 3 5 6 7

Sample Output

2
題目大意:一個青蛙要過河,每次跳的距離爲s-t之間,河裏有若干個石頭,問青蛙要過河最少須要跳的石頭數。
分析:動態規劃+狀態壓縮
一、若是橋的距離比較少那麼能夠直接解,詳情見鄺斌學長博客:http://www.cnblogs.com/kuangbin/archive/2012/02/27/2369901.html
二、本題的橋長度很大,蛋根據題目能夠知道石頭是不多的,就是說石頭與石頭之間(把橋的兩端也當作石頭)的距離是很小的,而青蛙跳的距離範圍很小,那麼有很大一部分區域是沒有石頭的,青蛙跳這些距離跟等價於沒有跳這些距離,因此咱們要作的就是將橋的距離壓縮到與其等價的較小的距離裏,固然要保證是同樣的。s t最大爲10。因此咱們能夠將石頭的距離mod 110(稍微大點,具體值最小值應爲lcm(s,t))既能夠壓縮,那麼接下來就是1裏面的問題了。
注意:特別的若是s,t相等,那麼青蛙只能是間隔s的距離跳,這個時候就不能壓縮了,單獨判斷(也很好判)。
 1 #include<iostream>
 2 #include<cstdio>
 3 #include <algorithm>
 4 using namespace std;
 5 int  l,a[102],s,t,n;
 6 int  dp[3300000],d[3300000];
 7 int main()
 8 {
 9     scanf("%d%d%d%d",&l,&s,&t,&n);
10     for(int i=1; i<=n; ++i)
11         scanf("%d",&a[i]);
12     int num;
13     if(s==t)
14     {
15         num=0;
16         for(int i=1; i<=n; i++)
17             if(a[i]%s==0) num++;
18         printf("%d\n",num);
19     }
20     else
21     {
22         int  tmp;
23         sort(a+1,a+n+1);
24         a[n+1]=l;
25         for(int  i=1; i<=n; ++i)
26         {
27             if(a[i+1]-a[i]>100)
28                 a[i+1]=a[i]+(a[i+1]-a[i])%100;
29         }
30         l=a[n+1];
31         for(int  i=1; i<=n; ++i)
32             d[a[i]]=1;
33         for(int  i=1; i<=l+t; ++i)
34             dp[i]=0xFFFFFFF;
35         for(int i=s; i<=l+t; ++i)
36         {
37             for(int  j=s; j<=t; ++j)
38             {
39                 if(i>=j&&dp[i]>dp[i-j]+d[i])
40                     dp[i]=dp[i-j]+d[i];
41             }
42         }
43         num=0xFFFFFFF;
44         for(int i=l; i<=l+t; ++i)
45             num=min(num,dp[i]);
46         printf("%d\n",num);
47     }
48     return 0;
49 }
View Code

Problem H: 過河卒

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 42   Solved: 9
[ Submit][ Status][ Web Board]

Description

如圖,A 點有一個過河卒,須要走到目標 B 點。卒行走規則:能夠向下、或者向右。同時在棋盤上的任一點有一個對方的馬(如上圖的C點),該馬所在的點和全部跳躍一步可達的點稱爲對方馬的控制點。例如上圖 C 點上的馬能夠控制 9 個點(圖中的P1,P2 … P8 和 C)。卒不能經過對方馬的控制點。

棋盤用座標表示,A 點(0,0)、B 點(n,m)(n,m 爲不超過 20 的整數,並由鍵盤輸入),一樣馬的位置座標是須要給出的(約定: C<>A,同時C<>B)。如今要求你計算出卒從 A 點可以到達 B 點的路徑的條數。

Input

鍵盤輸入
B點的座標(n,m)以及對方馬的座標(X,Y){不用判錯}

Output

屏幕輸出
一個整數(路徑的條數)。

Sample Input

6 6 3 2

Sample Output

17

HINT

題目大意:給你一個n*m個棋盤。卒只能向下或向右走,有一匹馬在(x,y)馬邊上(9個)的的位置不能走,問從(0,0)到(n,m)有多少種走法。

分析:動態規劃。令dp[i][j]表示(0,0)到(i,j)的路徑數,那麼方程就是dp[i][j]=dp[i-1][j]+dp[i][j-1]。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #define maxlen 30
 5 #define INF -100000
 6 using  namespace std;
 7 long long  dp[30][30],visited[30][30];
 8 int n,m,x,y;
 9 int xx[]= {-2,-2,-1,-1, 1, 1, 2, 2};
10 int yy[]= {-1, 1,-2, 2,-2, 2,-1, 1};
11 int xxx[]={0,-1};
12 int yyy[]={-1,0};
13 int main ()
14 {
15     while(scanf("%d%d%d%d",&n,&m,&x,&y)!=EOF)
16     {
17         memset(dp,0,sizeof(dp));
18         dp[0][0]=1;
19         memset(visited,0,sizeof(visited));
20         visited[x][y]=visited[0][0]=1;
21         for(int i=0; i<8; ++i)
22         {
23             int nextx=x+xx[i];
24             int nexty=y+yy[i];
25             visited[nextx][nexty]=1;
26         }
27         for(int i=0; i<=n; ++i)
28         {
29             for(int j=0; j<=m; ++j)
30             {
31                 for(int k=0;k<2;++k)
32                 if(!visited[i][j])
33                 dp[i][j]+=dp[i+xxx[k]][j+yyy[k]];
34             }
35         }
36         printf("%lld\n",dp[n][m]);
37     }
38 }
View Code
相關文章
相關標籤/搜索