P9744 「KDOI-06-S」消除序列
前言
本来可以赛时 AC 的结果由于少判断了一种条件而错在了 \(3\) 和 \(4\) 这两个点,但是还是要说一声 @As_snow 太强了。
思路
我们发现对于一次查询,第一种操作最多使用一次,然后我们对于在第 \(i\) 个点使用操作一的代价是 \(lc_{i}+a_i+sumb_{i+1}-re_{i+1}\) 这里我们的 \(lc_i\) 代表在 \(1\sim i\) 中在且属于 \(p\) 集合的位置的 \(c\) 数组之和,然后 \(sumb_{i}\) 代表 \(\sum_{j=i}^{n} b_j\) 然后 \(re_i\) 代表在 \(i\sim n\) 中属于 \(p\) 集合的 \(b_j\) 之和,这个写出来会发现是 \(n^2\) 的。
那么我们来想如何优化,我们可以发现对于每一次选择只会出现两种情况。
- 取的 \(i\) 不属于 \(p\) 集合。
- 取的 \(i\) 属于 \(p\) 集合。
这里我们可以发现如果是第二种情况可以直接求出,那么我们只需要处理第一种情况,然后我们可以发现对于在 \(p_i+1 \sim p_{i+1}-1\) 之间的数的 \(lc_i\) 和 \(re_i\) 的值是不会变的那么我们的第一种情况只需要求出 \(a_i+sumb_{i+1}\) 的最小值即可,这里我们可以用线段树维护。
但是这里还有三种特殊情况需要特殊处理。
- 没有用到第一种操作,最小值为 \(sumb_1-re_1\)。
- 使用第一个操作的位置在 \(p_1\) 之前,这里的最小值为 \(Min_{1,p_1-1}-g_1\) 这里的 \(Min_{i,j}\) 就是 \(i\sim j\) 中 \(a_i+sum_{i+1}\) 的最小值。
- 使用第一个操作在 \(p_cnt\) 之后,这里的处理方式也和上一种像似,就不细讲了。
代码
#include <bits/stdc++.h>
using namespace std ;
#define i12 __int128
#define int long long
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define rep1(i,x,y) for(int i=x;i>=y;i--)
#define fire signed
int n,q;
const int N=5e5+10;
int a[N],b[N],c[N];
i12 g[N];
int in[N];
i12 sum[N];
struct node {
int l,r;
i12 Min;
} tr[N<<2];
void up(int x) {
tr[x].Min=min(tr[x*2].Min,tr[x*2+1].Min);
}
void build(int u,int l,int r) {
tr[u]= {l,r};
if(l==r) {
tr[u].Min=a[l]+sum[l+1];
return ;
}
int mid=l+r>>1;
build(u*2,l,mid);
build(u*2+1,mid+1,r);
up(u);
}
int Ans(int u,int l,int r) {
if(tr[u].l>=l&&tr[u].r<=r) {
return tr[u].Min;
}
int mid=tr[u].l+tr[u].r>>1,res=LONG_LONG_MAX;
if(mid>=l) res=min(res,Ans(u*2,l,r));
if(mid<r) res=min(res,Ans(u*2+1,l,r));
return res;
}
void print(int x) {
if(x>=10) print(x/10);
putchar(x%10+'0');
}
fire main() {
// freopen("s.out","r",stdin);
// freopen("s.in","w",stdout);
scanf("%lld",&n);
rep(i,1,n) scanf("%lld",&a[i]);
rep(i,1,n) scanf("%lld",&b[i]);
rep(i,1,n) scanf("%lld",&c[i]);
rep1(i,n,1) sum[i]=sum[i+1]+b[i];
build(1,1,n);
i12 ans=LONG_LONG_MAX;
rep(i,1,n) ans=min(ans,a[i]+sum[i+1]);
scanf("%lld",&q);
while(q--) {
int cnt=false;
scanf("%lld",&cnt);
if(!cnt) {
print(ans);
cout<<endl;
continue;
}
rep(j,1,cnt) scanf("%lld",&in[j]);
g[cnt+1]=false;
rep1(i,cnt,1) g[i]=g[i+1]+b[in[i]];
i12 res=LONG_LONG_MAX,now=0;
if(cnt==n) {
cout<<"0\n";
continue;
}
res=Ans(1,1,in[1]-1)-g[1];
res=min(res,sum[1]-g[1]);
rep(i,1,cnt) {
res=min(res,now+Ans(1,in[i-1]+1,in[i]-1)-g[i]);
now+=c[in[i]];
res=min(res,now+a[in[i]]+sum[in[i]+1]-g[i+1]);
}
res=min(res,now+Ans(1,in[cnt]+1,n));
print(res);
cout<<endl;
}
return false;
}
/*
7
10 1 6 9 4 2 4
0 5 2 3 0 1 4
4 1 4 1 5 3 5
1
2 2 6
*/

浙公网安备 33010602011771号