Title

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;
}
posted @ 2023-11-24 10:38  UncleSam_Died  阅读(20)  评论(0)    收藏  举报  来源