GSS1 - Can you answer these queries I
xiezheyuan · · 题解
简要题意
给你一个长度为
思路
翻了翻题解区没有动态 dp 的做法,所以在此给一个动态 dp 的做法供参考,这也是我做的第一道动态 dp 题。
首先考虑一个朴素的问题:
给出一个序列
a ,求出它的最大子段和。
对于这个问题,我们可以朴素的 dp,设
转移是容易的:
然后我们考虑构造转移矩阵,大概长这样:
需要满足
注意这里的乘法是指
然后我们考虑构造,首先构造第一行:
- 由于需要有
f_{i-1}+a_i 一项,所以F_{11} = a_i 。 - 由于需要有
a_i 一项,所以F_{13}=a_i 。
然后考虑第二行,发现
- 由于需要有
f_{i-1}+a_i 一项,所以F_{21}=a_i 。 - 由于需要有
g_{i-1} 一项,所以F_{22}=0 。 - 由于需要有
a_i 一项,所以F_{23}=a_i 。
最后考虑第三行,只需要令
其余的位置不参与转移,填
所以得到:
我们考虑如何递推,考察
由于广义矩阵乘法具有结合律,所以我们可以用线段树来维护上面那个求积式。
时间复杂度
代码
#include <bits/stdc++.h>
#define int long long
#define ls (i<<1)
#define rs (i<<1|1)
#define mid ((l+r)>>1)
using namespace std;
const int N = 1e5+5;
int n,q,a[N];
struct matrix{
int n,m,a[4][4];
int* operator[](int x){return this->a[x];}
explicit matrix(int N = 0, int M = 0) : n(N), m(M) {};
void clear(){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++) a[i][j] = INT_MIN;
}
}
void output(){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++) cout<<a[i][j]<<' ';
cout<<'\n';
}
}
};
matrix bdmtx(int i){
matrix ans(3, 3);
ans[1][1] = ans[1][3] = ans[2][1] = ans[2][3] = a[i];
ans[1][2] = ans[3][1] = ans[3][2] = INT_MIN;
ans[2][2] = ans[3][3] = 0;
return ans;
}
matrix operator*(matrix a,matrix b){
matrix c(a.n, b.m);
assert(a.m == b.n);
c.clear();
for(int k=1;k<=a.m;k++){
for(int i=1;i<=a.n;i++){
for(int j=1;j<=b.m;j++) c[i][j] = max(c[i][j], a[i][k] + b[k][j]);
}
}
return c;
}
matrix t[N<<2];
void build(int i, int l, int r){
if(l == r){
cin>>a[l];
t[i] = bdmtx(l);
return;
}
build(ls, l, mid);build(rs, mid + 1, r);
t[i] = t[rs] * t[ls];
}
matrix query(int ql, int qr, int i, int l, int r){
if(ql <= l && r <= qr){
// cout<<"Range: "<<l<<' '<<r<<'\n';
// t[i].output();
return t[i];
}
if(ql <= mid && !(qr > mid)) return query(ql, qr, ls, l, mid);
if(qr > mid && !(ql <= mid)) return query(ql, qr, rs, mid + 1, r);
return query(ql, qr, rs, mid + 1, r) * query(ql, qr, ls, l, mid);
}
int bf(int l, int r){
if(l == r) return a[l];
matrix ans(3, 1);
ans.clear();
ans[1][1] = ans[2][1] = a[l], ans[3][1] = 0;
for(int i=l+1;i<=r;i++) ans = bdmtx(i) * ans;
return (ans)[2][1];
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n;
build(1, 1, n);
cin>>q;
while(q--){
int l,r;
cin>>l>>r;
if(l == r){
cout<<a[l]<<'\n';
continue;
}
matrix ans;
ans.n = 3, ans.m = 1;
ans[1][1] = ans[2][1] = a[l], ans[3][1] = 0;
ans = query(l + 1, r, 1, 1, n) * ans;
cout<<ans[2][1]<<'\n';
}
return 0;
}