G - Specified Range Sums 解説 by en_translator
Out of nowhere, let us replace the constraints \(\sum_{j=l}^{r} A_j = S_i\) with \(B(k) = \sum_{i=1}^{k} A_i\) for convenience.
Then, the constraint \(\sum_{j=l}^{r} A_j = S_i\) is substituted by \(B_{r} - B_{l-1} = S\).
Let us rephrase the constraints on the sequence using \(B\):
- \(B_{R_i} - B_{L_i-1} = S_i\) ( \(1 \le i \le M\) )
- \(B_{j} - B_{j-1} \ge 1\) ( \(1 \le j \le N\) )
We further deform the constraints to turn the equality into inequalities.
- \(B_{R_i} - B_{L_i-1} \ge S_i\) ( \(1 \le i \le M\) )
- \(B_{R_i} - B_{L_i-1} \le S_i\) ( \(1 \le i \le M\) )
- \(B_{j} - B_{j-1} \ge 1\) ( \(1 \le j \le N\) )
The problem to be solved is represented as the following linear programming (LP) problem:
\[ \begin{aligned} &\text{minimize} & & B_N \\ &\text{subject to} & & B_{R_i} - B_{L_i-1} \ge S_i \ ( 1 \le i \le M ) \\ & & & B_{R_i} - B_{L_i-1} \le S_i \ ( 1 \le i \le M ) \\ & & & B_{j} - B_{j-1} \ge 1\ ( 1 \le j \le N ) \end{aligned} \]
Here, notice that all the constraints are represented in the form \(B_i + c \ge B_j\). This is a special variant of LP that is easier to solved, and informally called Cow Game (in Japanese competitive programming community). Article 1 Article 2 Article 3 Article 4 Article 5 (all in Japanese)
(The name Cow Game originates from a problem arranging cows, which caused the trick widely known. Judge 1 Judge 2)
The objective function of the original Cow Game is maximizing a specific variable, but one can set the following LP to obtain that form.
The answer to the original problem is \(-1\) times the optimal value for the objective function of the following LP.
\[ \begin{aligned} &\text{maximize} & & B_0 \\ &\text{subject to} & & B_{R_i} - B_{L_i-1} \ge S_i \ ( 1 \le i \le M ) \\ & & & B_{R_i} - B_{L_i-1} \le S_i \ ( 1 \le i \le M ) \\ & & & B_{j} - B_{j-1} \ge 1\ ( 1 \le j \le N ) \\ & & & B_N = 0 \\ \end{aligned} \]
All that left is to construct an appropriate graph according to the form of the LP, and solve the shortest-path problem using Bellman-Ford algorithm.
Sample code (C++):
#include<bits/stdc++.h>
using namespace std;
int main(){
long long n,m;
cin >> n >> m;
vector<long long> l(m),r(m),s(m);
for(long long i=0;i<m;i++){
cin >> l[i] >> r[i] >> s[i];
}
vector<array<long long,3>> eg;
for(long long i=1;i<=n;i++){
eg.push_back({i,i-1,-1});
}
for(long long i=0;i<m;i++){
eg.push_back({r[i],l[i]-1,-s[i]});
eg.push_back({l[i]-1,r[i],s[i]});
}
// for(auto &nx : eg){
// cout << nx[0] << " -> " << nx[1] << " : " << nx[2] << "\n";
// }
vector<long long> d(n+1,8e18);
d[n]=0;
bool upd;
for(long long tr=0;tr<2*(n+m)+5;tr++){
upd=false;
for(auto &nx : eg){
long long nd=d[nx[0]]+nx[2];
if(d[nx[1]] > nd){
d[nx[1]]=nd;
upd=true;
}
}
}
if(upd){cout << "-1\n"; return 0;}
cout << -d[0] << "\n";
return 0;
}
投稿日時:
最終更新: