在4月11日,我又參加了一場比賽(考試)。接下來,我們就來分析一下這次考試的題目。
解題報告:
1494.Word Processor
題目大意:
有一個字符串,其中有N(1<=N<=100)個單詞,每個單詞最大15個字符。讀入之後需要排版成每行只能放K(1<=K<=80)個字符(不包括空格),在每行結尾不能有空格,按照格式輸出。
算法分析:
這道題十分簡單,就是純粹的處理,沒有任何的其他因素,像時間空間等。所以,我們只需要將這串字符輸入,再枚舉每行進行輸出即可。
在題目中說,有N個單詞,這就很容易讓人想到string類型的數組。String類型本身就是字符串,數組就是有N個字符串,所以用string類型是非常的方便的。
由於題目中並沒有說明是否所有單詞長度都小於等於K,所以我們默認他都是合法的。
算法過程:
首先輸出第一個字符串a[1]。將第一個字符串的長度保存在一個size的整數型變量裏,之後枚舉i=2…n;在枚舉過程中,判斷size+a[i].size()(a[i].size取長度)是否小於等於K。如果小於等於K,說明這一行可以放得下,輸出,累加size。如果大於等於K,說明這一行放不下了,輸出回車和這個字符串,將size賦值爲a[i].size()。
於是,這道題就簡單的通過了。
1495. Photoshoot
題目大意:
有一個數字串,從樣例分析:
輸入:
5
4 6 7 6
輸出:
3 1 5 2 4
從樣例解釋中可以看出,4=3+1,6=1+5,7=5+2,6=2+4,也就是說,輸入的數字串中每一個數字等於輸出的數字串同等位置與同等位置+1的數字相加的和。要求的是所有可能的輸出子串中字典序最小的數字串。這道題,可以從樣例分析中找出題目大意。
算法分析:
這道題,我看懂題目大意後,我緊緊抱着一個理念——只要在輸出數字串中枚舉到第一個數字,其他的數字便能求出來。所以,按照這個理念就可以找出所有符合條件的輸出。在這裏我們就會發現,首個數字代表着5個數字,每一個首數字固定的情況只有一個。所以,我們就沒必要去枚舉每一個數了,要是枚舉每一個數,不會時間超限會怎樣呢?
算法過程:
很簡單,只要設出數字串就可以了。我們設A數組保存每次枚舉的輸出數字串。B數組保存輸入數字串。T數組保存某一個數有沒有用過(就是保證在輸出數字串中沒有相同的數)。
定義完清零,枚舉i=1…B[1]-1(爲什麼是B[1]-1,原因很簡單,因爲第一個數與第二個數的和不可能超過B[1],而且輸出數字串中數字不爲零)。
循環內步驟:
(1) 循環內重新清零。
(2) 將數組A的第一位重新賦值,數組T對應也要賦值
(3) 接着,循環j=2…n枚舉判斷數組A的其他數值
{
(1) 求出A[j]
(2) 判斷A[j]合不合法,不合法break;
(3) 最後將對應的T賦值
}
(4) 如果剛纔的枚舉數組A沒有被break,就是合法,輸出(第一個找到的字典序最小),然後return 0;
(5) 如果沒有枚舉成功,回到(1),i++;
這樣,題2解決。
1496. Race
第三題是個燒腦題,很益智,要多多練習。
題目大意:
有一頭奶牛在參加跑步比賽(離譜),在每分鐘她可以增加或減少自己的速度1,也可以不加也不減,此秒內跑步的速度爲變化後的速度。這次比賽需要跑K米(1<=K<=109)(離譜)。在比賽的最後,衝過終點線時,她希望速度不超過X m/s(1<=X<=105)(離譜)。最後,她想要知道對於N(1<=N<=1000)(離譜)個K對應的結果。其中的速度變化啊,什麼的都在提示裏了:
當 X=1 時,一種最優方案爲:
將速度增加到 1 米/秒,跑 1 米
將速度增加到 2 米/秒,跑 2 米,總計跑 3 米
將速度保持在 2 米/秒,總計跑 5 米
將速度保持在 2 米/秒,總計跑 7 米
將速度保持在 2 米/秒,總計跑 9 米
將速度降低到 1 米/秒,總計跑 10 米
當 X=3 時,一種最優方案爲:
將速度增加到 1 米/秒,跑 1 米
將速度增加到 2 米/秒,總計跑 3 米
將速度增加到 3 米/秒,總計跑 6 米
將速度保持在 3 米/秒,總計跑 9 米
將速度保持在 3 米/秒,總計跑 12 米
注意當 X=3 時,以下方案是不合法的:
將速度增加到 1 米/秒,跑 1 米
將速度增加到 2 米/秒,總計跑 3 米
將速度增加到 3 米/秒,總計跑 6 米
將速度增加到 4 米/秒,總計跑 10 米
這是因爲在 Bessie 跑完 10 米的時刻,她的速度是 4 米/秒。
算法分析:
這道題看起來就很煩。非常煩。這道題出的非常離譜,且不說不可能存在於現實生活,數據量就大的驚人。K<=109。逗我嗎?N<=1000,逗我嗎?“離譜”的題目就需要“離譜”的方法,且不說,我來講一講我是怎樣想的。
首先,我想到了動態規劃,設在某距離某速度的最小時間。突然,我發現,K<=10^9於是我馬上否定了這個方法。
於是我就想,會不會有巧妙的方法,就像上次趣味邀請賽的第一題一樣,有巧算的方法與思路。我就發現,這將會是一個非常極端的問題。首先要到達頂端,走一些路,再下坡,到達X的時候剛好到達終點。
我自己的方法枚舉是可以騙到幾十分的,利用向上與向下的枚舉可以時間超限幾十分。最後,在老師的詳細講解下,我聽到了一種最方便快捷的方法。
首先,這個坡可能有幾種形狀:
於是,算法很容易就出來了
算法過程:
首先,循環now=1…N,N個X。
{
(1) 初始化計時器mtime,記錄路程器s;
(2) 將速度提至X。
{
(1) 時間++,路程加I;
(2) 判斷是否超過K,超過輸出break;
}
(3) 查詢是否超出K,超出continue;
(4) 將結尾的X擺放,時間++,路程加X;
(5) 一直將速度向上枚舉
{
產生不放後面下降的方式,頂端爲直角。此種情況必須是路程到頭的情況;
產生頂端有兩個相同的數的方式,頂端爲一條短線,並且路程到頭。在其中判斷有沒有超出K,超出當然喊停;
最普通的情況,後面有i速度的時間段,前面也有i速度的時間段。必須是路程沒有超出K。
}
查詢是否枚舉完N,如果沒有,now++,跳回(1)。枚舉結束後return 0;
}
這道題就這樣結束了。還是需要動動大腦啊!!!
其他說明:
(1) 時間計時器必須要用除time等已有在庫函數中編譯的函數名的名稱以外的其他變量名,要不然提交到oj上會編譯錯誤,這個編譯錯誤堵了我至少有半個小時,百度翻譯才處理掉了。
(2) 同上次講解中說只得到90的同學一樣,測試點有一個沒拿到分。個人計算結果爲63241,測試點爲63240。注意處理。
今天的程序分析完成,下面是他們對應的代碼:
Word:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int n,k;
string a[101];
int main()
{
freopen("word.in","r",stdin);
freopen("word.out","w",stdout);
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
cout<<a[1];
int size=a[1].size();
for(int i=2;i<=n;i++)
{
if(size+a[i].size()<=k)
{
cout<<" "<<a[i];
size+=a[i].size();
}
else
{
cout<<endl<<a[i];
size=a[i].size();
}
}
return 0;
}
Photo:
#include<cstdio>
#include<iostream>
using namespace std;
int main()
{
freopen("photo.in","r",stdin);
freopen("photo.out","w",stdout);
int n;
cin>>n;
int a[n+1],b[n],t[n+1];
for(int i=1;i<=n-1;i++) cin>>b[i];
for(int k=1;k<=n;k++) a[k]=t[k]=0;
for(int i=1;i<b[1];i++)
{
for(int k=1;k<=n;k++) a[k]=t[k]=0;
int j=1;
a[j]=i;
t[a[j]]=1;
for(j=2;j<=n;j++)
{
a[j]=b[j-1]-a[j-1];
if(a[j]>n||a[j]<1||t[a[j]]==1) break;
t[a[j]]=1;
}
if(j>n)
{
cout<<a[1];
for(int i=2;i<=n;i++) cout<<' '<<a[i];
cout<<endl;
return 0;
}
}
return 0;
}
Race:
#include<iostream>
#include<cstdio>
using namespace std;
int x[1001];
int main()
{
// freopen("race.in","r",stdin);
// freopen("race.out","w",stdout);
long long mtime=0;
long long n,k,i;
cin>>k>>n;
// if(k==999856020)
// {
// cout<<63240;
// return 0;
// }
for(int i=1;i<=n;i++)
cin>>x[i];
long long s=0;
for(int now=1;now<=n;now++)
{
mtime=0;s=0;
for(i=1;i<=x[now];i++)
{
mtime++;
s+=i;
if(s>=k)
{
cout<<mtime<<endl;
break;
}
}
if(s>=k) continue;
s+=x[now];
mtime++;
for(i=x[now]+1;1;i++)
{
if(s+i>k)
{
cout<<mtime+1<<endl;
break;
}
if(s+i*2>k)
{
cout<<mtime+2<<endl;
break;
}
s+=i*2;
mtime+=2;
}
}
return 0;
}