感觉要用差分来做,但是不知道咋做
#include<bits/stdc++.h>using namespace std;const int N=2e5+10;int a[N];int get(int x,int y)
{if(x%y==0) return x/y;return x/y+1;
}void solve()
{int n;cin>>n;for(int i=0;i<n;i++) cin>>a[i];long long ans=0;int t=a[n-1];for(int i=n-2;i>=0;i--){if(a[i]<=t){t=a[i];continue;}int res=get(a[i],t);ans+=res-1;t=a[i]/res;}cout<<ans<<endl;
}int main()
{ios::sync_with_stdio(false);cin.tie(nullptr);int t;cin>>t;while(t--)solve();return 0;
}
原来不是差分,是贪心
B B B 题应该基本上都是基本算法
贪心
该题主要是牵一发而动全身,我们从前面往后考虑不好处理,因为不知道会不会把一个数分割之后会不会比后面的数大,每一次操作可以保证比相邻的后面一个数字小,但是更后面的难以保证,所以从后面往前面维护更加合理
要求按照非严格单增排序,所以维护一个最小值,只要不严格小于最小值即可
初始化最小值为最后一个元素,也就是代码中的 t t t
要使得操作的次数尽可能小,也就是分的次数尽可能小,就是要分出来的数字尽可能大,但是分的次数不能大于最小值,所以贪心的策略是,每一次找到一个最大的小于最小值的数字(不严格小于)
要使得每一个数字都比较接近,这样才可以分出来的每一个数字都不严格小于最小值,所以用 ⌈ a [ i ] t ⌉ \lceil\frac{a[i]}t\rceil ⌈ta[i]⌉ 表示分出来的数字的个数,向上取整可以用特例来归纳证明,比如说 1 1 1 3 3 3 2 2 2 , 3 3 3 拆分成 1 1 1 和 2 2 2 ,拆分出来的数字的个数是 2 2 2 ,拆分的操作次数是 2 − 1 2-1 2−1 ,拆分出来最小的数字是 ⌊ a [ i ] r e s ⌋ \lfloor\frac{a[i]}{res}\rfloor ⌊resa[i]⌋ , r e s res res 表示的是拆分出来的数字的个数
一个数字的范围是 1 0 9 10^9 109 ,最多可以拆成 1 0 9 10^9 109 个 1 1 1 ,有 2 ⋅ 1 0 5 2\cdot10^5 2⋅105 个元素,所以会超出 i n t int int 的数据范围,要使用 l o n g long long l o n g long long 来记录答案
向上取整函数
int get(int x,int y)
{if(x%y==0) return x/y;return x/y+1;
}