2542 咖啡和作业
你要完成一个mm页的作业,手里有nn杯咖啡,每一杯咖啡有一个咖啡因强度值aiai,能支撑你写aiai页作业。每一天你会选择一些咖啡喝掉,对于当天喝的第i杯咖啡,咖啡因的强度会减弱i−1i−1单位,减到00就不再减小。问你最少经过几天能完成作业。
输入
第一行两个正整数n,m。
第二行n个数表示a[1…n]。
n<=100,m<=10000,1<=a[i]<=100。
输出
如果无解,输出-1;
否则输出最少天数。
输入样例
5 8
2 3 1 1 2
输出样例
4
题解:动态规划我们要考虑 状态的表示 和 状态转移方程,对于本题很显然我们可以用二维数组来表示
f[i][j]表示第i天喝第j杯咖啡能得到的最大咖啡因。转移方程也很显而易见,就是前一天的上一杯和今天的上一杯转移过来,因为前一天上一杯的状态转移过来可能会小于今天上一杯的咖啡因,所以我们需要临时储存下前一天转移来的状态。
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 110;
int f[N][N], a[N],vis[N][N];
int n, m, ans = 1e6;
bool cmp(int x, int y)
{
return x > y;
}
int main()
{
cin >> n >> m;
int sns = 0;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
sns += a[i];
}
sort(a + 1, a + n + 1, cmp);
if (sns < m)
{
cout << -1 << endl;
return 0;
}
else
{
f[1][1]=a[1];
vis[1][1]=1;
int s=f[1][1];
for(int j=2;j<=n;j++)
{
if(a[j] > vis[1][j-1])
// f[1][j] = f[1][j-1] - vis[1][j-1] + a[j];
s = s - vis[1][j-1] + a[j];
// else
// f[1][j]=f[1][j-1];
f[1][j]=max(s,f[1][j]);
vis[1][j]=vis[1][j-1] + 1;
if(f[1][j]>=m)
ans=min(ans,1);
}
for (int i = 2; i <= n; i++)
{
for (int k = i; k <= n; k++)
{
// f[i][k] = f[i-1][k-1] + a[k];
s = f[i-1][k-1] + a[k];
f[i][k]=max(f[i][k],s);
vis[i][k] = 1;
if(f[i][k]>=m)
ans=min(ans,i);
for(int j= k + 1;j <= n;j++)
{
if(a[j] > vis[i][j-1])
s = s - vis[i][j-1] + a[j];
// f[i][j] = f[i][j-1]-vis[i][j-1] + a[j];
// else
// f[i][j]=f[i][j-1];
f[i][j] = max(s,f[i][j]);
vis[i][j]=vis[i][j-1] + 1;
if(f[i][j]>=m)
ans=min(ans,i);
}
}
}
}
// 3 2 2 1 1
// for(int i=1;i<=n;i++)
// {
// for(int k=1;k<=n;k++)
// cout<<f[i][k]<<" ";
// puts("");
// }
cout << ans << endl;
return 0;
}