题解 GDFZOJ 2020普转提十连测day5
零、写在前面
看原比赛戳这儿
本来昨天比的赛昨天就要写题解,但是Dp真的是太难刷啦!!!(\(for\ example:\)1、2、3)所以被Dp的题解耽误了许多时间,所以只好今天来写了
本次比赛题目难度:普及+提高-
\(emm,emm\),主要是考察了概率与期望方面的内容
一、T1 铺设道路
看原题戳这儿
1、审题
春春是一名道路工程师,负责铺设一条长度为 \(n\) 的道路。
铺设道路的主要工作是填平凹凸不平的地表。整段道路可以看作是 \(n\) 块首尾相连的区域,一开始,第 \(i\) 块区域的高度为 \(d_i\) 。
春春每天可以选择一段连续区间 \([L,R]\) ,让其高度增加或减少\(1\) 。
春春希望你能帮他设计一种方案,可以在最短的时间内使得整段道路相邻两个位置的高度差的绝对值都小于等于 \(k\) 。注意第 \(1\) 个和第 \(0\) 个位置以及第 \(n\) 个和第 \(n+1\) 个位置的高度差的绝对值也不能大于 \(k\) 。在这里,我们认为第 \(0\) 个位置和第 \(n+1\) 个位置的高度是 \(0\) 且不能被更改。
数据范围:\(1\le n\le 100000,-100000\le d_i\le 100000,0\le k\le 100000\)
乍一看到这道题,铺设道路?春春?这不是\(NOIP2018\)提高的题吗?还有代码,直接\(Ctrl+V\)上去,水题!可是\(······\)
为什么?
2、分析
不同之处
我们来对比一下这两道题:\(NOIP2018:\text{可以在最短的时间内将整段道路的下陷深度都变为 0}\);这道题\(:\text{可以在最短的时间内使得整段道路相邻两个位置的高度差的绝对值都小于等于 k}\)。
好吧,还真不一样,不能单纯地去比大小,需要加一点东西
相同之处
但是我们又发现了,除了这两句话之外不都是一样的吗?仔细看一看,好像还真是一样的,那肯定可以用差不多的方式来做,但是不能照抄
3、做题
那就开始做题吧
首先我们发现如果\(d_i \gt d_{i-1}+k\)的话,d_i就必须至少要减去\(aa_i-(aa_{i-1}+k)\)才能满足条件所以我们可以用一个\(ans1\)记录下来,即\(ans1+=aa_i-aa_{i-1}-k\),反之,如果\(d_i \lt d_{i-1}+k\)的话,我们就用一个\(ans2\)记录下来,即\(ans2+=aa_{i-1}-aa_i-k\)
然后我们发现了一个规律,当我们求出\(ans1\)和\(ans2\)之后,我们就可以直接输出这其中的最大值了,为什么?
我们发现\(ans1\)和\(ans2\)的部分是可以抵消的,抵消后剩下的部分再加上\(ans1\)和\(ans2\)中小的哪一个数就是答案了,这不就是\(max(ans1,ans2)\)吗?
所以我们就顺利地把这道题给切掉了
4、代码
#include<bits/stdc++.h>
using namespace std;
long long int a,b,c,d,ans1,ans2;
int aa[100001];
int main()
{
scanf("%lld%lld",&a,&b);
for(int i=1;i<=a;++i) scanf("%lld",aa+i);
for(int i=1;i<=a+1;++i)
{
if(aa[i]-aa[i-1]>b) ans1+=aa[i]-aa[i-1]-b;
if(aa[i]-aa[i-1]<-b) ans2+=aa[i-1]-aa[i]-b;
}
printf("%lld",max(ans1,ans2));
return 0;
}
/*
6 1
4 3 2 5 3 5
*/
二、T2 拒绝压行
看原题戳这儿
1、审题
乍一看,呀,这是什么题嘛,其实······
将题意简化一下:有一个长度为\(n\)的数列,去掉其中的一个数之后,统计剩下的逆序对的数量,请问当去掉第几个数的时候,剩下的逆序对数量最多
数据范围:\(1 \le n \le 5000,1 \le a_i \le 109\)
好吧,这是一道水题(不需要加删除线)
2、做题
首先我们要求出这个数列里面一共有多少个逆序对\(c\),求出每一个数能造成的逆序对的最大值\(ans\),最后用\(c-ans\)就是答案啦
注:因为本题数据过水,\(O(n^2)\)都可以过,所以直接循环就好了,不需要用归并
3、代码
#include<bits/stdc++.h>
using namespace std;
int a,b,c,d,ans;
int aa[1000001];
int main()
{
scanf("%d",&a);
for(int i=1;i<=a;++i) scanf("%d",aa+i);
for(int i=1;i<=a;++i)
{
int tot=0;
for(int j=1;j<i;++j) if(aa[j]>aa[i]) tot++;
for(int j=i+1;j<=a;++j) if(aa[j]<aa[i]) tot++;
c+=tot,ans=max(ans,tot);
}
printf("%d",c/2-ans);
return 0;
}
三、晓美焰的逃亡
四、吸血鬼
看原题戳这儿
1、审题
在第\(0\)天,有\(n-1\)个人和\(1\)个吸血鬼。每天只有两个人见面。如果它们属于同一物种,那就是什么也不会发生,也就是说,一个人遇到一个人或一个吸血鬼遇到一个吸血鬼。否则,人们可能会以概率\(p\)变成吸血鬼。现在请计算所有人都变成吸血鬼的天数的数学期望。
又是一道概率期望题呢,不过这道题明显比上一题简单
2、做题
因为每天至多有一个人转化为吸血鬼,考虑第i个人转化为吸血鬼的期望天数\(D_i\);那么所有人转化为吸血鬼的期望天数\(ans=D_1+D_2+…+D_{n-1}\),;
第\(i\)个人转化为吸血鬼的概率为\(p_i\),则第\(i\)个人转化为吸血鬼服从几何分布;故\(D_i=1/p_i\),而\(p_i=p * i * (n-i)/(n*(n-1)/2)\),所以我们就可以得到公式
那么我们就可以在\(O(n)\)的时间内得到\(ans\)值,\(very\ good!!!\)
3、代码
#include<bits/stdc++.h>
using namespace std;
double a,b,c,d,ans;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%lf%lf",&a,&b);ans=0;
for(int i=1;i<=a-1;++i) ans+=(a*(a-1.0)*1.0)/(b*i*(a-i)*2.0);
printf("%.3lf\n",ans);
}
return 0;
}