 /**//*
一個郵筒理論上能承受的最大爆破值為m,則實際在范圍[1,m]
現在要測試它的實際爆破值
如果只有一個郵筒的話,就需要從小到大測試直到破
最壞情況下,到最后才破
那就需要測試1,2, ,m 總共需要(m+1)*m/2數量的火藥了
注:上一次測試沒爆的話,郵筒還是完好的
但如果有多個郵筒,則可以不用測試那么多次
如2個的話,第一次測試t ,1<=t<=m
爆:下次就要測試[1,t-1] 只剩下一個郵筒,
不爆:繼續用當前的郵筒,測試[t+1,m]
所以dp[k,i,j]表示還剩下k個郵筒,爆破值的范圍在[i,j],為測出爆破值至少需要的火藥
枚舉t,則可以由dp[k-1,i,t-1],dp[k,t+1,j]轉移過來
由于事先不知道,為了使火藥足夠,所以只能取最大值 max(dp[k-1,i,t-1],dp[k,t+1,j])
但為了最少的測試,所以枚舉t,得到最少需要的火藥
dp[k,i,j] = min{t+max(dp[k-1,i,t-1],dp[k,t+1,j])}
參考
http://hi.baidu.com/accplaystation/blog/item/c78b13522de9300d0df3e328.html
*/
#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
#include<stack>
#include<queue>
#include<cmath>
#include<string>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<set>
#include<list>
#include<numeric>
#include<cassert>

using namespace std;

const int INF = 1000000000;

int dp[11][101][101];

int main()
  {
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
#endif
 for(int i = 1 ; i <= 100 ; i ++) {
 for(int j = i ; j <= 100 ;j++) {
dp[1][i][j] = (j-i+1)*(j+i)/2;
}
}
 for(int k = 2 ; k <= 10 ; k++) {
 for(int j = 100 ; j > 0 ; j--) {
 for(int i = j; i > 0 ; i--) {//dp[k,j,j] = j
dp[k][i][j] = INF;
 for(int t = i; t <= j ; t++) {
dp[k][i][j] = min(dp[k][i][j] , t + max(dp[k][t+1][j] , dp[k-1][i][t-1]));
}
}
}
}
int T;
 for(scanf("%d",&T); T-- ;) {
int k , m;
scanf("%d%d",&k,&m);
printf("%d\n",dp[k][1][m]);
}

return 0;
}
|