12年的神题啊写了2天
50 分钟一个n^2预处理的暴力 拿了70分
感觉性价比挺高的
县贴个代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define inf 0x3fffffff
using namespace std;
//by mars_ch
int n,m;
int min1,min2;
struct data
{
int h,id;
}c[1000005];
int nexta[1000005],nextb[1000005],s;
int disa[100005];
int disb[100005];
int x0;
void dfs(int st,int x,int suma,int sumb,int p,int z)
{
if(p == 1) //a
{
if(suma+sumb+abs(c[x].h-c[nexta[x]].h)>z || nexta[x] == 0)
{
disa[st]=suma;
disb[st]=sumb;
return ;
}
suma+=abs(c[x].h-c[nexta[x]].h);
dfs(st,nexta[x],suma,sumb,2,z);
}
else
{
if(suma+sumb+abs(c[x].h-c[nextb[x]].h)>z || nextb[x] == 0)
{
disa[st]=suma;
disb[st]=sumb;
return ;
}
sumb+=abs(c[x].h-c[nextb[x]].h);
dfs(st,nextb[x],suma,sumb,1,z);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&c[i].h);
}
for(int i=1;i<=n;i++)
{
min1=inf,min2=inf;
for(int j=i+1;j<=n;j++)
{
if(abs(c[i].h-c[j].h)<min1)
{
min2=min1;
nexta[i]=nextb[i];
min1=abs(c[i].h-c[j].h);
nextb[i]=j;
}
else if(abs(c[i].h-c[j].h)<min2 && abs(c[i].h-c[j].h)!=min1)
{
min2=abs(c[i].h-c[j].h);
nexta[i]=j;
}
else if(abs(c[i].h-c[j].h) == min1 && c[j].h>c[nextb[i]].h)
{
min2=min1;
nexta[i]=j;
}
else if(abs(c[i].h-c[j].h) == min1 && c[j].h<c[nextb[i]].h)
{
min2=min1;
nexta[i]=nextb[i];
nextb[i]=j;
}
}
}
/*for(int i=1;i<=n;i++)
{
printf("%d %d\n",nexta[i],nextb[i]);
}*/
scanf("%d",&x0);
/*************第一问************/
double ans=1.0*0x3fffffff;
double res=0.0;
for(int k=1;k<=n;k++)
{
dfs(k,k,0,0,1,x0);
if(disb[k] == 0) res=1.0*0x3fffffff;
else res=1.0*disa[k]/disb[k];
if(res<ans)
{
ans=res;
s=k;
}
}
printf("%d\n",s);
/***************第二问*****************/
memset(disa,0,sizeof(disa));
memset(disb,0,sizeof(disb));
int ss,xx;
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&ss,&xx);
memset(disa,0,sizeof(disa));
memset(disb,0,sizeof(disb));
dfs(ss,ss,0,0,1,xx);
printf("%d %d\n",disa[ss],disb[ss]);
}
}
中间 就一个小细节 就是 注意 精度问题 所以建议除数的时候改成乘法
但是突然想到了个问题:好像没有处理 第一问如果相等时的 海拔高点啊
数据很巧妙啊。。。也挺好改的吧 加上一个判等于,记录一下前驱ok?
然后思考正解 其实 lyd讲过所以知道 set加 倍增。
set很神奇啊 一个自己维护奇奇怪怪的结构体,但是很好用。对于这道题只用找左边两个右边两个 比较一下就ok嗯
倍增不说啥了
mark long long 的神奇输出
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<set>
#include<iostream>
#define maxn 100005
using namespace std;
//by mars_ch
int n;
int disa[maxn][20],disb[maxn][20],f[maxn][20];
int nexta[maxn],nextb[maxn];
struct city
{
int pos,h;
bool operator < (const city &b) const{
return h<b.h;
}
}c[maxn];
struct data
{
int pos,dif;
bool operator < (const data &b) const
{
if(dif!=b.dif) return dif<b.dif;
return c[pos].h<c[b.pos].h;
}
}t[6];
int read()
{
int s=0,f=1;
char p=getchar();
while((p<'0' || p>'9') && p!='-') p=getchar();
if(p == '-') f=-1,p=getchar();
while(p>='0' && p<='9') s=s*10+p-'0',p=getchar();
return f*s;
}
set<city> s;
inline void query(int St, int X,long long &ta,long long &tb)
{
for (int i = 18; ~i; -- i)
if (f[St][i] && disa[St][i] + disb[St][i] <= X)
{
ta += disa[St][i]; tb =tb+ disb[St][i];
//cout<<"XXX"<<tb<<" "<<disb[St][i]<<endl;
X -= disa[St][i] + disb[St][i]; St = f[St][i];
}
//cout<<"asdasd "<<tb<<endl;
int posa = nexta[St]; if (!posa) return;
int dis = abs(c[posa].h - c[St].h); if (dis <= X) ta += dis;
}
void find(int x)
{
set<city> :: iterator it=s.find(c[x]);
int tot=0;
if(it!=s.begin())
{
--it;t[++tot]=(data){it->pos,abs(it->h-c[x].h)};
if(it!=s.begin())
{
--it;t[++tot]=(data){it->pos,abs(it->h-c[x].h)};++it;
}
++it;
}
if((++it)!=s.end())
{
t[++tot]=(data){it->pos,abs(it->h-c[x].h)};
if((++it)!=s.end())
{
t[++tot]=(data){it->pos,abs(it->h-c[x].h)};--it;
}
--it;
}
sort(t+1,t+tot+1);
nextb[x]=t[1].pos;
if(tot==1) return;
nexta[x]=t[2].pos;
}
int main()
{
n=read();
for(int i=1;i<=n;i++)
{
c[i].h=read();
c[i].pos=i;
}
for(int i=n;i>=1;i--)
{
s.insert(c[i]);
if(i!=n)find(i);
}
for(int i=1;i<=n;i++)
{
int p1=nexta[i],p2=nextb[nexta[i]];
disa[i][0]=p1?abs(c[i].h-c[p1].h):0;
disb[i][0]=p2?abs(c[p2].h-c[p1].h):0;
f[i][0]=p2;
}
for(int j=1;j<=18;j++)
{
for(int i=1;i<=n;i++)
{
f[i][j]=f[f[i][j-1]][j-1];
disa[i][j]=disa[i][j-1]+disa[f[i][j-1]][j-1];
disb[i][j]=disb[i][j-1]+disb[f[i][j-1]][j-1];
}
}
int x0=read();
int ans = 0;
long long ansa = 1e15, ansb = 0ll;
for (int i = 1; i <= n; ++ i) {
long long ta = 0, tb = 0;
query(i, x0,ta,tb);
// cout<<"11111 "<<tb<<endl;
//printf(" %d %d \n",ta,tb);
if (tb && (!ans || ansa * tb > ansb * ta)) {
ansa = ta; ansb = tb; ans = i;
}
}
printf("%d\n",ans);
/****************第二问********/
int m;
m=read();
for(int i=1;i<=m;i++)
{
int ss=read(),xx=read();
long long ta=0,tb=0;
query(ss,xx,ta,tb);
// cout<<ta<<" "<<tb<<endl;
printf("%lld %lld\n",ta,tb);
}
}