1. Wannafly挑战赛3- A 珂朵莉
题面:给你一个长 n 的序列,m 次查询 。每次查询给一个 x,然后: 从序列的最左端 1 开始,每次随机的选择一个右端点 r,如果两个端点间的区间和不超过 x ,就进行一次分割,然后把左端点变成 r + 1, 否则一直随机下去。 问这样分割出来的期望段数
思路:dp[i]表示[i,n]的期望段数,Sum[i]表示[i,n]区间dp和。假设R为i为起点时满足条件的最右端,区间[i,R]内处处等可能分割,分割点为k时,[i,k]为1段,后面分割的期望为dp[k+1],所以总期望dp[k+1]+1,而分割点可取[i,R],故:dp[i]=sum{dp[t+1]+1|i<=t<=R}/(R-i+1)。
1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 const int maxn = 100010; 5 int n, m; 6 int A[maxn]; 7 double dp[maxn],Sum[maxn];//dp[i]表示[i,n]的期望段数 8 //Sum[i]表示[i,n]区间dp和 9 10 int main() 11 { 12 scanf("%d%d", &n, &m); 13 int maxnum = -1; 14 for (int i = 1; i <= n; i++) scanf("%d", A + i),maxnum=max(maxnum,A[i]); 15 while (m--) 16 { 17 int x; 18 scanf("%d", &x); 19 if (x < maxnum) printf("cumt acm up up!\n"); 20 else 21 { 22 dp[n] = Sum[n] = 1; 23 Sum[n+2]=Sum[n + 1] = 0.0;//设置边界,方便后边(Sum[i+1]-Sum[R+1]) 24 int tmp = 0,R=n; 25 for (int i = n; i >= 1; i--) 26 { 27 tmp += A[i]; 28 if (tmp > x) 29 { 30 while (tmp > x) tmp -= A[R--]; 31 } 32 //区间[i,R]内处处等可能分割,分割点为k时,[i,k]为1段,后面分割的期望为dp[k+1],所以总期望dp[k+1]+1,而分割点可取[i,R],故: 33 //dp[i]=sum{dp[t+1]+1|i<=t<=R}/(R-i+1) 34 dp[i] = 1.0 + (Sum[i + 1] - Sum[R + 2]) / (1.0*R - i + 1); 35 Sum[i] = Sum[i + 1] + dp[i]; 36 } 37 printf("%.2lf\n", dp[1]); 38 } 39 } 40 return 0; 41 }