CF1898B Milena and Admirer 题解
题目大意
已知有一个长度为 $n$ 的正整数序列 $a$,现在你可以做若干次以下操作,使得 $a$ 单调不下降:
- 选择一个 $1\le i\le n$;
- 选择一个整数数 $1\le x<a_i$;
- 将 $a_i$ 分成两个正整数 $x$ 和 $a_i-x$ 并重新插入序列中,插入规则如下:
- 设操作前的序列为 $a_1,a_2,a_3,\dots,a_i,\dots,a_k$,操作后的序列为 $a_1,a_2,a_3,\dots,x,a_i-x,\dots,a_k$。
解题思路
我们很容易发现,对于所有的 $a_i$,操作后有 $x<a_i,a_i-x<a_i$,也就是说,所有的 $a_i$ 只能通过操作使得值变小,而不可能增加。那么,我们从后往前更新值。读者自证不难,如果 $\exists a_i>a_{i+1}$,那么把 $a_i$ 均分为若干部分使得每部分的值小于 $a_{i+1}$ 且最大是最优决策。
由上可得,我们的操作如下:
- 若 $a_i\le a_{i+1}$,不做任何操作;
- 若 $a_i>a_{i+1}$,那么我们把 $a_i$ 均分为 $\displaystyle cnt=\left \lceil \frac{a_i}{a_{i+1}} \right\rceil$,个部分,答案 $ans=ans+cnt-1$,但是这个时候不需要更新 $a_i$ 的值,也不需要插入值。接下来,我们把 $a_i$ 更新为 $\displaystyle \left\lfloor \frac{a_i}{cnt} \right \rfloor$。
注意事项
考虑到 $a_i\le 10^9$,那么 $ans$ 需要开 long long。
AC 代码
码风较丑,不喜勿喷。
#include<math.h>
#include<time.h>
#include<stdio.h>
#include<algorithm>
#define ll long long
#define N 200005
int n,a[N];
inline void work(){
scanf("%d",&n);ll ans=0;
for(register int i=1;i<=n;++i)
scanf("%d",&a[i]);
for(register int i=n-1;i>=1;--i){
if(a[i]>a[i+1]){
int cheu=ceil((a[i]*1.0)/(a[i+1]*1.0));
int res=a[i]%cheu;ans+=(ll)cheu-1;
a[i]=a[i]/cheu;
}else continue;
}printf("%lld\n",ans);
}signed main(){
srand(114514);
srand(rand());
srand(time(0));
int T;scanf("%d",&T);
while(T--) work();
return 0;
}

浙公网安备 33010602011771号