T1 区间的价值
Description
我们定义“区间的价值”为一段区间的最大值*最小值。
一个区间左端点在L,右端点在R,那么该区间的长度为(R−L+1)。
现在聪明的杰西想要知道,对于长度为k的区间,最大价值的区间价值是多少。
当然,由于这个问题过于简单。
我们肯定得加强一下。
我们想要知道的是,对于长度为1∼n的区间,最大价值的区间价值分别是多少。
由于某种不可抗力, 的值将会是1~10^9 内随机产生的一个数。(除了样例)
Solution
没想到这题是这么水
关键在于加粗的那句话。
因为有了那句话,所以只要会暴力就能过==(当然不是裸的暴力)
我的做法是枚举一个最小值,然后暴力求向两边找到的一直满足该元素是最小值的位置。
然后判一下就好了。
期望是log 1.6 n
证明:
对于当前元素,如果它是最小的元素,那么要循环n次
若是次小,那么期望n/2次
若第三小,那么期望是n/3次
以此类推,第几小期望循环次数就是n/几。
这样的总期望是莫约log 1.6 n
当然ShinFeb大神是有更好的解法的,不想我这半吊子的期望,而且他是logn
当然他跑的比我慢==
unicornt的做法跟我差不多,但他的启发式好像更明显。所以他比我略快。。
比赛的时候竟然没A真是可惜。。
但总比unicornt看了一个小时还没A好==
[源代码]
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int M=1e5+5;
int n,A[M];ll ans[M],tmp[M];
inline void rd(int &a){
a=0;char c;
while(c=getchar(),!isdigit(c));
do a=a*10+(c^48);
while(c=getchar(),isdigit(c));
}
inline void Max(int &a,int b){if(a<b)a=b;}
inline void Max(ll &a,ll b){if(a<b)a=b;}
inline void gao(){
memset(ans,0,sizeof(ans));
for(int i=1;i<=n;++i)rd(A[i]);
for(int i=1;i<=n;++i){
int mx=0,p1=i,p2=i;
Max(ans[1],1ll*A[i]*A[i]);
for(int j=i-1;j;--j){
if(A[j]<A[i])break;
Max(mx,A[j]);
Max(tmp[i-j+1],1ll*A[i]*mx);
p1=j;
}
mx=0;
for(int j=i+1;j<=n;++j){
if(A[j]<A[i])break;
Max(mx,A[j]);
Max(tmp[j-i+1],1ll*mx*A[i]);
p2=j;
}
ll Mx=0;
for(int i=1;i<=p2-p1+1;++i){
Max(Mx,tmp[i]);
Max(ans[i],Mx);
tmp[i]=0;
}
}
for(int i=1;i<=n;++i)
printf("%I64d\n",ans[i]);
}
int main(){for(;cin>>n;)gao();}
T4 货物运输
Description
公元2222年,l国发生了一场战争。
小Y负责领导工人运输物资。
其中有m种物资的运输方案,每种运输方案形如li,ri。表示存在一种货物从li运到ri。
这里有n个城市,第i个城市与第i+1个城市相连(这里1号城市和n号城市并不相连),并且从i号城市走到i+1号或者从i+1号走到i号需要耗费1点时间。
由于高科技的存在,小Y想到了一种节省时间的好方案。在X号城市与Y号城市之间设立传送站,只要这么做,在X号城市走到Y号城市不需要耗费时间,同样的,从Y号城市走到X号城市也不需要耗费时间。
但是为了防止混乱,只能设立这么一条传送站。
现在这些运输方案同时进行,小Y想让最后到达目的地的运输方案时间最短。
在样例中,存在两条运输方案,分别是1号城市到3号与2号到4号,那么我们在2号城市与3号城市建立传送站,这样运输方案时间最长的只需要1点时间就可以了。
Solution
这是一道很好的数形结合。
首先我们可以想到二分(当然我一开始想到的是三分==)
对于二分出的答案,我们对于每一对l和r都可以得到满足他们的x和y的位置(这大概是一个菱形)
然后对于这么多个菱形求交。
我本来是想记录一个最右的左端点,以及一个最左的右端点,还有最下的上端点以及最上的下端点,然而这样并不对==
正解应该是解一个不等式
设二分的距离为p
可以列出方程|l-x|+|y-r|<=p
分零点讨论一下再取交集就可以==
[源代码]
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int M=1e6+5;
const int INF=1<<30;
int l[M],r[M],n,m;
inline void Min(int &x,int y){if(x>y)x=y;}
inline void Max(int &x,int y){if(x<y)x=y;}
inline bool check(int q){
int mx1=-INF,mx2=-INF,mi1=INF,mi2=INF;
for(int i=1;i<=m;++i){
if(r[i]-l[i]<=q)continue;
Max(mx1,l[i]+r[i]-q);
Min(mi1,l[i]+r[i]+q);
Max(mx2,l[i]-r[i]-q);
Min(mi2,l[i]-r[i]+q);
}
return mx1<=mi1&&mx2<=mi2;
}
inline void rd(int &a){
a=0;char c;
while(c=getchar(),!isdigit(c));
do a=a*10+(c^48);
while(c=getchar(),isdigit(c));
}
inline void gao(){
for(int i=1;i<=m;++i){
rd(l[i]),rd(r[i]);
if(r[i]<l[i])swap(r[i],l[i]);
}
int L=1,R=n,ans;
while(L<=R){
int mid=L+R>>1;
if(check(mid))R=mid-1,ans=mid;
else L=mid+1;
}
printf("%d\n",ans);
}
int main(){
for(;~scanf("%d %d",&n,&m);)gao();
}