P12503 「ROI 2025 Day1」索契游乐园 题解
P12503 「ROI 2025 Day1」索契游乐园 题解
知识点
二分,三分,贪心,数学。
分析
首先可以知道我们可以把折返的贡献分为两边独立的贡献,只要一边移动的贡献设为 \(t\),另一边设为 \(2t\) 即可。
那么将坐标 \(<x_0\) 和 \(>x_0\) 的分开到两个数组中,重新将距离设为 \(|x-x_0|\)(\(x=x_0\) 的随便处理,反正毫无贡献)。
尝试列出贡献表达式,设 \(c\) 表示走了几个 \(d\):
那么 \(ct\) 的部分我们可以手算,\(\sum_{x_i\le cd}\min((x_i\bmod d)^2,(x_i - x_i \bmod d)^2)\) 我们可以前缀和预处理,\(\sum_{x_i > cd} (x_i-cd)^2\) 我们可以拆式子手算:
记号约定:
- \(i_0\) 是满足 \(x_i\le cd\) 的最大 \(i\)。
- \(sum_i\) 表示 \(\sum_{j=1}^i\min((x_i\bmod d)^2,(x_i - x_i \bmod d)^2)\)。
- \(suf_i\) 表示 \(\sum_{j=i+1}^nx_j\)。
- \(suf2_i\) 表示 \(\sum_{j=i+1}^nx_j^2\)。
然后可以三分求解(如何证明呢?不知道,略略略),复杂度 \(O(m(\log_2{n}+\log_{\frac{3}{2}}{V}))\),但是,吼吼吼,过不了怎么办?
注意到表达式是一个二次函数的形式(除了 \(i_0=n\) 的时候):
那么每一段预处理后,可以直接用公式求出大概的最值位置,然后找到最近的 \(d\) 的倍数即可,那么三分部分复杂度变为 \(O(\log_{\frac{3}{2}}{n})\)。
最后再用二分代替整数域三分,复杂度 \(O(m\log_2{n})\),可能还要一堆乱搞卡常才可以过……
发现其实点的位置随 \(t\) 递减是单调递增的(如何证明呢?还是不知道,略略略略略),所以我们直接离线询问尺取做到 求解部分 只有 \(O(n+m)\),就可以过了!!!
最后的复杂度:如果你愿意写基排,那么就是 \(O(n+m)\)(大常数警告),不然也只有排序的 \(O(n\log_2{n}+m\log_2{m})\),常数很小。
代码
#define Int __int128
#define Fi first
#define Se second
#define Pii pair<int,int>
constexpr int N(3e5+10),Qr(6e5+10);
int n,m,D,Q,X,tot;
int ta[N],a[N];
ll sum[N],suf[N];
ll ans[Qr][2][2];
Int suf2[N];
Pii pos[N];
struct Query {
int t,idx;
friend bool operator <(const Query &a,const Query &b) { return a.t>b.t; }
} Que[Qr<<1];
int pre(int x) { return x/D*D; }
int nxt(int x) { return (x+D-1)/D*D; }
ll sq(ll x) { return x*x; }
Int f(ll A,Int B,int x) { return (Int)A*x*x+B*x; }
Int calc(int t,int p) {
if(p>tot)return (ll)(a[m]+D-1)/D*t+sum[m];
const int l(pos[p-1].Fi+1),r(pos[p].Fi),x(pos[p].Se);
const ll A((ll)D*D*(m-x+1));
const Int B(t-(Int)2*D*suf[x]);
const int mid(-B/(2*A));
Int ans(0);
if(l<=mid&&mid<=r) {
ans=f(A,B,mid);
if(mid<r)tomin(ans,f(A,B,mid+1));
} else ans=f(A,B,r<mid?r:l);
return ans+sum[x-1]+suf2[x];
}
void Solve(const bool ty) {
if(!m)return;
tot=0,pos[0].Fi=-1,suf[m+1]=0,suf2[m+1]=0;
FOR(i,1,m) {
sum[i]=sum[i-1]+min(sq(a[i]-pre(a[i])),sq(a[i]-nxt(a[i])));
if(i<=1||pre(a[i])!=pre(a[i-1]))pos[++tot]= {a[i]/D,i};
}
DOR(i,m,1)suf[i]=suf[i+1]+a[i],suf2[i]=suf2[i+1]+sq(a[i]);
int it(1);
FOR(i,1,Q) {
while(it<=tot&&calc(Que[i].t,it)>calc(Que[i].t,it+1))++it;
const int &idx(Que[i].idx);
(idx>0?ans[idx][ty][0]:ans[-idx][ty][1])=calc(Que[i].t,it);
}
}
signed main() {
/*DE("Input & Query");*/
I(n);
FOR(i,1,n)I(ta[i]);
I(X,D,Q);
FOR(i,1,Q) {
int t;
I(t),Que[(i<<1)-1]= {t,i},Que[i<<1]= {t<<1,-i};
}
Q<<=1;
/*DE("Solve");*/
sort(ta+1,ta+n+1),sort(Que+1,Que+Q+1);
// left
m=0;
DOR(i,lower_bound(ta+1,ta+n+1,X)-ta-1,1)a[++m]=X-ta[i];
Solve(0);
// right
m=0;
FOR(i,upper_bound(ta+1,ta+n+1,X)-ta,n)a[++m]=ta[i]-X;
Solve(1);
/*DE("Output");*/
Q>>=1;
FOR(i,1,Q)O(min(ans[i][0][0]+ans[i][1][1],ans[i][0][1]+ans[i][1][0]),'\n');
return 0;
}

浙公网安备 33010602011771号