F. Education
题意:
t组样例(t <= 1e4)
每组样例给你n , c
a[1] , a[2] ........ a[n]
b[1] , b[2] .........b[n-1]
(n <= 2e5 , c <= 1e9)
c表示目标的金钱
如果你在等级i
你每天可以赚a[i]的钱
当然你在这一天也可以不赚钱
升级你的等级
如果你的等级在i
升级到i+1级需要b[i]的钱
你一开始在第1个等级
问赚到至少c钱的最小天数
数据保证 a递增
a[1] <= a[2] <= a[3] <= ........ <= a[n]
思路:
一看感觉是个dp
每天都有2种选择
要么赚钱,要么升级
假设f[i][j]为当前在第i天,等级为j的情况下所赚的最大钱的数量
考虑一下状态转移方程
i这天赚钱
f[i][j] = max( f[i][j],f[i-1][j] + a[j] )
或者在i这天升级
当然前提是f[i][j] >= b[j]
f[i][j] = max( f[i][j] , f[i-1][j-1] - b[j] )
然后考虑一下时间复杂度
O tn^2
一定超时
这。。。。。
只能换一种思路
那在考虑一下,一共最多n个等级
假设只升到i这个等级
并且在i这个等级赚了c钱
所需要的最小天数
如果可以 o1 算出来的话,我们可以枚举所有等级
更新最小值
那么
设cost[i]数组表示只在等级i赚到c钱的最小天数
所以cost[i] 等于 先升到i这个等级在赚够c的最小天数
cost[1] = ⌈ c a [ 1 ] ⌉ \lceil \frac{c}{a[1]} \rceil ⌈a[1]c⌉
cost[2] = ⌈ b [ 1 ] a [ 1 ] ⌉ \lceil \frac{b[1]}{a[1]} \rceil ⌈a[1]b[1]⌉ + ⌈ c a [ 2 ] ⌉ \lceil \frac{c}{a[2]} \rceil ⌈a[2]c⌉ + 1
cost[3] = ⌈ b [ 1 ] a [ 1 ] ⌉ \lceil \frac{b[1]}{a[1]} \rceil ⌈a[1]b[1]⌉ + ⌈ b [ 2 ] a [ 2 ] ⌉ \lceil \frac{b[2]}{a[2]} \rceil ⌈a[2]b[2]⌉ + ⌈ c a [ 3 ] ⌉ \lceil \frac{c}{a[3]} \rceil ⌈a[3]c⌉ + 1 + 1
cost[4] =
⌈
b
[
1
]
a
[
1
]
⌉
\lceil \frac{b[1]}{a[1]} \rceil
⌈a[1]b[1]⌉ +
⌈
b
[
2
]
a
[
2
]
⌉
\lceil \frac{b[2]}{a[2]} \rceil
⌈a[2]b[2]⌉ +
⌈
b
[
3
]
a
[
3
]
⌉
\lceil \frac{b[3]}{a[3]} \rceil
⌈a[3]b[3]⌉ +
⌈
c
a
[
3
]
⌉
\lceil \frac{c}{a[3]} \rceil
⌈a[3]c⌉ + 1 + 1 + 1
…
cost[n] = ⌈ b [ 1 ] a [ 1 ] ⌉ \lceil \frac{b[1]}{a[1]} \rceil ⌈a[1]b[1]⌉ + ⌈ b [ 2 ] a [ 2 ] ⌉ \lceil \frac{b[2]}{a[2]} \rceil ⌈a[2]b[2]⌉ + ⌈ b [ 3 ] a [ 3 ] ⌉ \lceil \frac{b[3]}{a[3]} \rceil ⌈a[3]b[3]⌉ + … + ⌈ b [ n − 1 ] a [ n − 1 ] ⌉ \lceil \frac{b[n-1]}{a[n-1]} \rceil ⌈a[n−1]b[n−1]⌉ + ⌈ c a [ n ] ⌉ \lceil \frac{c}{a[n]} \rceil ⌈a[n]c⌉ + (n - 1)
对上面这个式子稍微解释一下
因为升级需要单独一天
所以末尾要加上升级的天数
这个式子还没有考虑到一个问题
你升级的时候,假设现在已经赚了7元钱
你升级需要6元钱
那么你升级之后还剩下1元钱
所以你还需要一个h[i] 数组表示
升级到i这个等级所剩下的钱
那么
cost[1] =
⌈
c
a
[
1
]
⌉
\lceil \frac{c}{a[1]} \rceil
⌈a[1]c⌉
cost[2] = ⌈ b [ 1 ] a [ 1 ] ⌉ \lceil \frac{b[1]}{a[1]} \rceil ⌈a[1]b[1]⌉ + ⌈ c − h [ 2 ] a [ 2 ] ⌉ \lceil \frac{c-h[2]}{a[2]} \rceil ⌈a[2]c−h[2]⌉ + 1
cost[3] = ⌈ b [ 1 ] a [ 1 ] ⌉ \lceil \frac{b[1]}{a[1]} \rceil ⌈a[1]b[1]⌉ + ⌈ b [ 2 ] − h [ 2 ] a [ 2 ] ⌉ \lceil \frac{b[2]-h[2]}{a[2]} \rceil ⌈a[2]b[2]−h[2]⌉ + ⌈ c − h [ 3 ] a [ 3 ] ⌉ \lceil \frac{c-h[3]}{a[3]} \rceil ⌈a[3]c−h[3]⌉ + 1 + 1
cost[4] =
⌈
b
[
1
]
a
[
1
]
⌉
\lceil \frac{b[1]}{a[1]} \rceil
⌈a[1]b[1]⌉ +
⌈
b
[
2
]
−
h
[
2
]
a
[
2
]
⌉
\lceil \frac{b[2]-h[2]}{a[2]} \rceil
⌈a[2]b[2]−h[2]⌉ +
⌈
b
[
3
]
−
h
[
3
]
a
[
3
]
⌉
\lceil \frac{b[3]-h[3]}{a[3]} \rceil
⌈a[3]b[3]−h[3]⌉ +
⌈
c
−
h
[
4
]
a
[
3
]
⌉
\lceil \frac{c-h[4]}{a[3]} \rceil
⌈a[3]c−h[4]⌉ + 1 + 1 + 1
…
cost[n] = ⌈ b [ 1 ] a [ 1 ] ⌉ \lceil \frac{b[1]}{a[1]} \rceil ⌈a[1]b[1]⌉ + ⌈ b [ 2 ] − h [ 2 ] a [ 2 ] ⌉ \lceil \frac{b[2]-h[2]}{a[2]} \rceil ⌈a[2]b[2]−h[2]⌉ + ⌈ b [ 3 ] − h [ 3 ] a [ 3 ] ⌉ \lceil \frac{b[3]-h[3]}{a[3]} \rceil ⌈a[3]b[3]−h[3]⌉ + … + ⌈ b [ n − 1 ] − h [ n − 1 ] a [ n − 1 ] ⌉ \lceil \frac{b[n-1]-h[n-1]}{a[n-1]} \rceil ⌈a[n−1]b[n−1]−h[n−1]⌉ + ⌈ c − h [ n ] a [ n ] ⌉ \lceil \frac{c-h[n]}{a[n]} \rceil ⌈a[n]c−h[n]⌉ + (n - 1)
那么考虑一下怎么用o1的时间求出上面的式子
我们可以发现前面的
⌈ b [ 1 ] a [ 1 ] ⌉ \lceil \frac{b[1]}{a[1]} \rceil ⌈a[1]b[1]⌉ + ⌈ b [ 2 ] − h [ 2 ] a [ 2 ] ⌉ \lceil \frac{b[2]-h[2]}{a[2]} \rceil ⌈a[2]b[2]−h[2]⌉ + ⌈ b [ 3 ] − h [ 3 ] a [ 3 ] ⌉ \lceil \frac{b[3]-h[3]}{a[3]} \rceil ⌈a[3]b[3]−h[3]⌉ + … + ⌈ b [ n − 1 ] − h [ n − 1 ] a [ n − 1 ] ⌉ \lceil \frac{b[n-1]-h[n-1]}{a[n-1]} \rceil ⌈a[n−1]b[n−1]−h[n−1]⌉
可以用前缀和s[]数组来优化
这样就可以做到 o1 时间来更新
考虑一下加上s这个数组
上面的式子变成了
cost[1] = s[1] + ⌈ c a [ 1 ] ⌉ \lceil \frac{c}{a[1]} \rceil ⌈a[1]c⌉
cost[2] = s[2] + ⌈ c − h [ 2 ] a [ 2 ] ⌉ \lceil \frac{c-h[2]}{a[2]} \rceil ⌈a[2]c−h[2]⌉ + 1
cost[3] = s[3] + ⌈ c − h [ 3 ] a [ 3 ] ⌉ \lceil \frac{c-h[3]}{a[3]} \rceil ⌈a[3]c−h[3]⌉ + 1 + 1
cost[4] = s[4] +
⌈
c
−
h
[
4
]
a
[
4
]
⌉
\lceil \frac{c-h[4]}{a[4]} \rceil
⌈a[4]c−h[4]⌉ + 1 + 1 + 1
…
cost[n] = s[n] + ⌈ c − h [ n ] a [ n ] ⌉ \lceil \frac{c-h[n]}{a[n]} \rceil ⌈a[n]c−h[n]⌉ + (n - 1)
注意一下c++里面取整默认为下取整
所以
⌈
a
b
⌉
\lceil \frac{a}{b} \rceil
⌈ba⌉ =
a
−
b
+
1
b
\frac{a-b+1}{b}
ba−b+1
所以最后的答案为 min( c o s t i cost_i costi) [1 <= i <= n ]
最终代码如下
时间复杂度:O tn
#include<bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define re register int
#define pll pair<int,int>
#define x first
#define y second
#define sf(x) scanf("%d",&x)
#define sfl(x) scanf("%lld",&x)
typedef long long ll ;
using namespace std;
const int N = 1e6 + 10 , M = 1010 , inf = 0x3f3f3f3f , mod = 1e9 + 7 ;
ll t , n , c ;
ll a[N] , b[N] ;
ll s[N] ; // s[i]数组表示前缀和的最小天数
ll h[N] ; // h[i]表示升级到i这个等级剩下的钱
int main()
{
cin >> t ;
while(t--)
{
cin >> n >> c ;
fer(i,1,n) sfl(a[i]) ;
fer(i,1,n-1) sfl(b[i]) ;
s[1] = 0 , h[1] = 0 ;
// s[1] , h[1] 初始化为0 ,方便后面计算
ll have = 0 ; // have 表示上一轮剩下的钱
fer(i,2,n)
{
if(have >= b[i-1])//如果上一轮剩下的钱足够升级,那直接升级
{
s[i] = s[i-1] ;
have = have - b[i-1] ;
h[i] = have ;
}
else
{
s[i] = s[i-1] + (b[i-1] - have + a[i-1] - 1) / a[i-1] ;
if( (b[i-1] - have) % a[i-1] == 0) have = 0 ;
else have = a[i-1] - (b[i-1] - have) % a[i-1] ;
// 在草稿纸上推一下就可以得到have的表达式
h[i] = have ;
}
}
ll res = 1e18 ;
fer(i,1,n)
{
res = min(res,s[i] + (c - h[i] + a[i] - 1) / a[i] + (i - 1)) ;
}
// fer(i,1,n) cout << h[i] << " " ;
// cout << "\n" ;
cout << res << "\n" ;
}
return 0;
}
原创不易 点个赞在走呗