题解 P8983 【「DROI」Round 1 失控】
闲话:出题人曾经转移那部分的问题抽象之后丢到洛谷讨论区里问过,我当时顺手就回答了一下然后 std 用了我的做法,没想到这次遇上了!
全新出题方式,学到了!!1
但是这个题是有性质的,可以做到更优的复杂度。
为了方便考虑,我们加入操作
那么每行我们都必须选择一个操作进行且不能进行连续两次非零操作。
考虑 dp,记
转移即考虑
若暴力枚举下一行进行哪个操作,检验是否合法,时间复杂度
考虑优化,首先若非零操作在最后一行,那么下一行只能进行操作
那么现在剩下的情况就是最后一行为操作
考虑对于每个下一个进行的操作快速找出哪些
于是条件变为两行加的数不能都不在区间里,我们枚举
可以对于每个操作维护出
最后,对于
时间复杂度
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=55;
const int M=305;
const int K=2e3+5;
int n,m,k,C,a[N][M],p[M],q[M],A[K],B[K],dp[N][2][K],pos[K],b[K],st[11][K],Log[K];
signed main() {
ios::sync_with_stdio(false),cin.tie(0);
cout.precision(10),cout.setf(ios::fixed);
cin>>n>>m>>k>>C;
for (int i=1;i<=n;i++) {
for (int j=1;j<=m;j++) {
cin>>a[i][j];
}
}
for (int i=1;i<=m;i++) {
cin>>p[i];
}
for (int i=1;i<=m;i++) {
cin>>q[i];
}
for (int i=1;i<=k;i++) {
cin>>A[i];
b[i]=A[i];
}
for (int i=1;i<=k;i++) {
cin>>B[i];
}
b[k+1]=0;
sort(b+1,b+k+2);
int cnt=unique(b+1,b+k+2)-b-1;
for (int i=0;i<=k;i++) {
pos[i]=lower_bound(b+1,b+cnt+1,A[i])-b;
}
for (int i=2;i<=cnt;i++) {
Log[i]=Log[i/2]+1;
}
memset(dp,0x3f,sizeof(dp));
for (int i=0;i<=k;i++) {
dp[1][i>0][i]=B[i];
}
for (int i=2;i<=n;i++) {
for (int j=1;j<=k;j++) {
dp[i][0][j]=dp[i-1][1][j];
}
vector<pair<int,int>>lim(k+1,make_pair(-(int)1e9,(int)1e9));
if (i>2) {
for (int j=1;j<=m;j++) {
int L1=(a[i-1][j]-C)-a[i-2][p[j]],R1=(a[i-1][j]+C)-a[i-2][p[j]];
int L2=(a[i-1][j]-C)-a[i][q[j]],R2=(a[i-1][j]+C)-a[i][q[j]];
for (int t=0;t<=k;t++) {
if (A[t]<L2||A[t]>R2) {
lim[t].first=max(lim[t].first,L1);
lim[t].second=min(lim[t].second,R1);
}
}
}
}
for (int j=1;j<=cnt;j++) {
st[0][j]=1e9+7;
}
for (int j=0;j<=k;j++) {
st[0][pos[j]]=min(st[0][pos[j]],dp[i-1][0][j]);
}
for (int j=1;j<11;j++) {
for (int t=1;t<=cnt;t++) {
st[j][t]=min(st[j-1][t],st[j-1][t+(1<<(j-1))]);
}
}
for (int x=0;x<=k;x++) {
bool flag=1;
if (i<n&&x) {
for (int j=1;j<=m;j++) {
if (abs(a[i][j]+A[x]-a[i-1][p[j]])>C&&abs(a[i][j]+A[x]-a[i+1][q[j]])>C) {
flag=0;
break;
}
}
}
if (!flag) {
continue;
}
int l=lower_bound(b+1,b+cnt+1,lim[x].first)-b;
int r=upper_bound(b+1,b+cnt+1,lim[x].second)-b-1;
if (l<=r) {
int k=Log[r-l+1];
int mn=min(st[k][l],st[k][r-(1<<k)+1]);
dp[i][x>0][x]=min(dp[i][x>0][x],mn+B[x]);
}
}
}
int ans=1e9+7;
for (int i=0;i<=k;i++) {
ans=min(ans,min(dp[n][0][i],dp[n][1][i]));
}
cout<<ans<<"\n";
return 0;
}