传送门:QAQQAQ
题意注意点:
1.是从前往后走,不能回头
2.小A小B轮流开,先小A开,而小A是到第二近的点(这点调试的时候查了好久)
3.若绝对值差相同海拔低的更近,而第一个询问若比值相同是海拔高的更优
思路:我们先预处理出离i点最近和次近点的编号,没有就是-1(链表可以达到O(n),但是用STL O(nlog(n)) 绰绰有余,代码量还小)
然后用倍增预处理出从i号点走2^j轮A走的路程,B走的路程,和走完这些轮最终停下的点(定义AB各走一次为一轮)
注意可能走半轮,即最后一下A走B不走。
写题过程:
大佬MYY告诉我不要心急,先打70分暴力,然后打了2个小时暴力(STL真的好难查啊QAQ) 打完暴力以后告诉我主程序要全部删掉重写。。。。。
看到直接旁边的HCY没打暴力直接正解AC,心态崩了。。。
然后就在没有特判掉走不到的情况和AB顺序一半写正,一半写反上调了好久,不过最终做出来还是蛮有成就感的(感觉自己很弱啊。。)
代码:
#include<bits/stdc++.h> #define m_k make_pair #define ll long long using namespace std; const ll N=102000; const ll inf=(ll)5e18; ll f[N][2],n,m,a[N],x0; //0:closest 1:second closest ll dp[N][20][2],Bits[20],p[N][20]; //0:disB 1:disA p:finalpos AB为一轮,走2^t轮 ll _abs(ll x) { if(x<0) return -x; else return x; } set<pair<ll,ll> > st; vector<pair<ll,ll> > tmp; void init() { memset(f,-1,sizeof(f)); st.insert(m_k(a[n],n)); st.insert(m_k(a[n-1],n-1)); f[n-1][0]=n; for(ll i=n-2;i>=1;i--) { ll bl=0; tmp.clear(); set<pair<ll,ll> > :: iterator it; it=st.lower_bound(m_k(a[i],i)); if(it!=st.end()) tmp.push_back(*it),it++,bl++; if(it!=st.end()) tmp.push_back(*it); if(bl) it--; it--; set<pair<ll,ll> > :: iterator be; be=st.begin(); be--; if(it!=be) tmp.push_back(*it),it--; if(it!=be) tmp.push_back(*it); ll ans1=inf,ans2=inf; for(ll j=0;j<(ll)tmp.size();j++) { if(ans1>_abs(a[i]-tmp[j].first)||(ans1==_abs(a[i]-tmp[j].first)&&a[f[i][0]]>tmp[j].first)) { f[i][1]=f[i][0]; ans2=ans1; f[i][0]=tmp[j].second; ans1=_abs(a[i]-tmp[j].first); } else if(ans2>_abs(a[i]-tmp[j].first)||(ans2==_abs(a[i]-tmp[j].first)&&a[f[i][1]]>tmp[j].first)) { f[i][1]=tmp[j].second; ans2=_abs(a[i]-tmp[j].first); } } st.insert(m_k(a[i],i)); } } void ready() { memset(p,-1,sizeof(p)); memset(dp,-1,sizeof(dp)); for(ll i=1;i<=n;i++) { ll pos=f[i][1]; if(pos==-1) continue; dp[i][0][1]=_abs(a[pos]-a[i]); if(f[pos][0]==-1) continue; dp[i][0][0]=_abs(a[pos]-a[f[pos][0]]); p[i][0]=f[pos][0]; } for(ll j=1;j<20;j++) { for(ll i=1;i<=n;i++) { for(ll k=0;k<=1;k++) if(dp[i][j-1][k]!=-1&&dp[p[i][j-1]][j-1][k]!=-1) dp[i][j][k]=dp[i][j-1][k]+dp[p[i][j-1]][j-1][k]; if(p[i][j-1]!=-1) p[i][j]=p[p[i][j-1]][j-1]; } } } ll suma,sumb; double calc(ll x,ll y) { if(y==0) return inf*1.0; return(x*1.0)/(y*1.0); } int main() { scanf("%lld",&n); for(ll i=1;i<=n;i++) scanf("%lld",&a[i]); init(); ready(); scanf("%lld",&x0); double ans=inf*1.0; ll now=0; a[0]=-inf; for(int i=1;i<=n;i++) { ll suma=0,sumb=0,pos=i; for(int j=19;j>=0;j--) { if(dp[pos][j][0]==-1||dp[pos][j][1]==-1||p[pos][j]==-1) continue; if(dp[pos][j][0]+dp[pos][j][1]+suma+sumb>x0) continue; suma+=dp[pos][j][1]; sumb+=dp[pos][j][0]; pos=p[pos][j]; } if(dp[pos][0][1]+suma+sumb<=x0&&dp[pos][0][1]!=-1) suma+=dp[pos][0][1]; if(ans>calc(suma,sumb)||(ans==calc(suma,sumb)&&a[i]>a[now])) { now=i; ans=calc(suma,sumb); } } cout<<now<<endl; ll pos; scanf("%lld",&m); for(int i=1;i<=m;i++) { scanf("%lld%lld",&pos,&x0); suma=0; sumb=0; for(int j=19;j>=0;j--) { if(dp[pos][j][0]==-1||dp[pos][j][1]==-1||p[pos][j]==-1) continue; if(dp[pos][j][0]+dp[pos][j][1]+suma+sumb>x0) continue; suma+=dp[pos][j][1]; sumb+=dp[pos][j][0]; pos=p[pos][j]; } if(dp[pos][0][1]+suma+sumb<=x0&&dp[pos][0][1]!=-1) suma+=dp[pos][0][1]; printf("%lld %lld ",suma,sumb); } return 0; }