提交
题目大意 建一座桥要安装支架,支架之间的距离不能超过d(两个位置之间),建支架的代价是
a
i
j
+
1
a_{ij}+1
aij+1 问建连续相邻的k座桥的最小代价是多少
分析
先求每座桥的代价,用前缀和算出连续k座(也可以用滑动窗口)
每座桥的代价如果用传统dp会超时,考虑优化,如果一个位置更加靠后且代价更小,是更优的,可以考虑用单调队列来维护,(维护一个单调递减队列),对于每个
a
i
j
a_{ij}
aij看是否和单调队列的距离满足d,满足的话计算价值添加到队列中,若不满足队头出队
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
using i128 = __int128;
#define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int n,m,k,d;
void solve(){
//如过一个点位置靠后,代价还小,那么更优
//位置越来越远,代价越来越大,访问一个点
//那这个点和他最近的那个那个支架,一定最前面满足位置空格
//用单调队列维护
cin>>n>>m>>k>>d;
vector<vector<i64>> mp(n+1,vector<i64>(m+1));
deque<i64> q;
vector<i64> p;
p.push_back(0);
for(int i = 1;i<=n;++i){
for(int j = 1;j<=m;++j){
cin>>mp[i][j];
}
}
for(int i = 1;i<=n;++i){
deque<pair<i64,int>> dq;
dq.push_back({1,1});
for(int j =2;j<=m;++j){
while(!dq.empty()&&j-dq.front().second-1>d) dq.pop_front();
i64 v = dq.front().first+mp[i][j]+1;
while(!dq.empty()&&dq.back().first>=v) dq.pop_back();
dq.push_back({v,j});
}
p.push_back(dq.back().first);
}
i64 ans = 0x3f3f3f3f3f3f3f3f;
for(int i = 1;i<=n;++i) p[i]+=p[i-1];
for(int i = k;i<=n;++i) ans = min(ans,p[i]-p[i-k]);
cout<<ans<<'\n';
}
signed main(){
ios;
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}