問題 K: 水果傳送
題目描述
聯歡會開始了,同學們按對應的組別已整齊安靜的就坐。此時小Z發現爲同學們準備的水果還沒有派發。各小組已緊密的連成了一排,於是他想了個辦法,從兩端將水果一個一個傳送給各組,直到滿足各組水果要求個數爲止。假設每秒他只能在兩端各傳送一個水果,求T秒後各組中的水果數。
傳送辦法是:各組拿到水果後都向中間方向的相鄰組傳送(最中間的不用傳),直到相鄰組滿足要求爲止。舉例:小組數M=5,各組要求水果數K=4。
第1秒
輸入
輸入三個正整數,分別是組數M,每組需要的水果數K,時間T,它們的範圍[1…100000]。
數據保證M爲奇數,K爲偶數。T<=M*K/2。
輸出
輸出傳送T秒後,各組別的水果數。
樣例輸入 Copy
5 4 5
樣例輸出 Copy
1 2 4 2 1
先附上我原本錯誤的答案,尾遞歸超時,無腦流,一次一次加。
這裏順便提一下#pragma GCC optimize(2)這個讀入掛,雖然可以在遇到大數據時幫您照樣輸出,但超時依舊,只是幫你檢查一下結果的作用。個人感覺沒什麼大用。
//尾遞歸超時
#include <bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
int m,k,t,a[50002],mid;
void dfs(int n){
if(n==t){
for(int i=1;i<=mid;i++){
if(i==1) printf("%d",a[i]);
else printf(" %d",a[i]);
}
for(int i=mid-1;i>0;i--){
printf(" %d",a[i]);
}
return;
}
else if(n==0){
a[1]++;
}
else{
a[1]++;
for(int i=mid-1;i>0;i--){
if(a[i]==0) continue;
else if(a[i+1]<k){
a[i]--;
if(i+1==mid) a[mid]+=2;
else a[i+1]++;
}
}
}
dfs(n+1);
}
int main(){
scanf("%d%d%d",&m,&k,&t);
mid=(m+1)/2;
dfs(0);
}
很明顯複雜度O(n)=O(x^n),當然尾遞歸(自上而下)也可以改善,降成O(n),比如備忘錄、二分查找、正序(自下而上)等等,但本質和找規律差不多(其實是有點區別的),下面給一種類二分的。
其實這題可以發現左右對稱,只有中間特殊,一遍的規律也很容易找出,所以就分類吧。
將它分成3種情況。
1、還沒到加到中間。
2、到中間了但是中間數沒有超過k值。
3、到中間了且超過k。
PS:這代碼還是小編自己抄別人的,自己實在太懶了。
#include <bits/stdc++.h>
using namespace std;
int a[100001];
int main(){
int mid,m,k,t,b,c;
scanf("%d%d%d",&m,&k,&t);
mid=m/2+1; //中間數
c=t-m/2; //剩下的時間
b=k/2; //半對半時間
if(t<mid){ //還沒到mid
for(int i=1; i<=t; i++) a[i]=1;
}
else if(t>=mid){
for(int i=1; i<mid; i++) a[i]=1; //初始化
if(c*2<=k) a[mid]=c*2; //mid還未至K
else if(c*2>k){ //mid已至K
t=c-k/2;
a[mid]=k;
for(int i=mid-1;i>0;i--){
if(t==0) break;
while(a[i]<k&&t){
a[i]++; t--;
}
}
}
}
//輸出
for(int i=1;i<=mid;i++){
if(i==1) printf("%d",a[i]);
else printf(" %d",a[i]);
}
for(int i=mid-1;i>0;i--) printf(" %d",a[i]);
return 0;
}