CF643C Levels and Regions
wind_whisper · · 题解
\text{Description}
有一种电子游戏,它由
现在,你要将这些关卡分成
然后,一名玩家将会从第
你需要找到一种划分方法,使得该玩家期望 AK 该游戏的期望时间最小。输出这个最小的期望时间。
\text{Solution}
一道乍看很吓人但是仔细想想并不难的小清新 dp 题。
有一个期望相关的常用结论:若一件事做成的概率是
证明:设期望次数为
移项即可得。
回到本题。
显然不同段之间互相独立。
设
那么本题
也就是:
对
然后直观感受可以发现,这个东西是满足决策单调性的。
感性理解一下就是要使全局尽可能小,前面的
直接上分治即可,时间复杂度
\text{Code}
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
const int N=2e5+100;
#define ll long long
inline ll read(){
ll x(0),f(1);char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m;
double sum[N],t[N];
double s1[N],s2[N];
inline double calc(int l,int r){
return (s1[r]-s1[l-1])-sum[l-1]*(s2[r]-s2[l-1]);
}
double dp[52][N];
void solve(int k,int l,int r,int tl,int tr){
if(l>r) return;
int mid=(l+r)>>1,pl(0);
for(int i=tl;i<=min(mid-1,tr);i++){
double w=dp[k-1][i]+calc(i+1,mid);
if(w<dp[k][mid]){
dp[k][mid]=w;pl=i;
}
}
solve(k,l,mid-1,tl,pl);solve(k,mid+1,r,pl,tr);
return;
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
n=read();m=read();
for(int i=1;i<=n;i++){
t[i]=read();
sum[i]=sum[i-1]+t[i];
s1[i]=s1[i-1]+sum[i]/t[i];
s2[i]=s2[i-1]+1.0/t[i];
}
for(int i=0;i<=m;i++){
for(int j=0;j<=n;j++) dp[i][j]=2e18;
}
dp[0][0]=0;
for(int k=1;k<=m;k++) solve(k,1,n,0,n-1);
printf("%lf\n",dp[m][n]);
return 0;
}
/*
*/