/**//* 一个邮筒理论上能承受的最大爆破值为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; }
|