結果
| 問題 |
No.2546 Many Arithmetic Sequences
|
| コンテスト | |
| ユーザー |
Nachia
|
| 提出日時 | 2023-11-25 01:37:01 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 176 ms / 2,000 ms |
| コード長 | 3,764 bytes |
| コンパイル時間 | 1,558 ms |
| コンパイル使用メモリ | 95,988 KB |
| 最終ジャッジ日時 | 2025-02-18 00:46:24 |
|
ジャッジサーバーID (参考情報) |
judge4 / judge4 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 36 |
ソースコード
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <utility>
#include <queue>
#include <atcoder/modint>
using namespace std;
using i64 = long long;
using u64 = unsigned long long;
#define rep(i,n) for(i64 i=0; i<(i64)(n); i++)
#define repr(i,n) for(i64 i=(i64)(n)-1; i>=0; i--)
const i64 INF = 4001001001001001001;
using Modint = atcoder::static_modint<998244353>;
struct LiChaoTree{
using Val = i64;
struct Func {
i64 a, b;
Val operator()(i64 x) { return a * x + b; }
};
static Func infFunc() { return { 0,INF }; }
int N;
vector<Func> V;
vector<bool> visited;
LiChaoTree(i64 n){
N = 1;
while(N < n) N *= 2;
V.assign(N*2, infFunc());
visited.assign(N*2, false);
}
void addSegment(i64 l, i64 r, Func f){
if(l >= r) return;
auto dfs = [&,this](int i,Func f,i64 a,i64 b,auto dfs) -> void {
visited[i] = true;
if(i >= V.size()) return;
if(r <= a || b <= l) return;
i64 m = (a+b)/2;
if(!(l <= a && b <= r)){
dfs(i*2,f,a,m,dfs);
dfs(i*2+1,f,m,b,dfs);
return;
}
bool greatf_l = !(V[i](a) < f(a));
bool greatf_r = !(V[i](b-1) < f(b-1));
if(!greatf_l && !greatf_r) return;
if(greatf_l && greatf_r){ V[i] = f; return; }
if(a + 1 == b) return;
if(!(V[i](m) < f(m))){
swap(V[i],f);
swap(greatf_l,greatf_r);
}
if(greatf_l) dfs(i*2,f,a,m,dfs);
else dfs(i*2+1,f,m,b,dfs);
};
dfs(1,f,0,N,dfs);
}
void addLine(Func f){
addSegment(0,N,f);
}
Val minVal(i64 p){
int i = 1;
Val res = infFunc()(p);
int l = 0, r = N;
while(i < V.size()){
if(!visited[i]) break;
res = min(res,V[i](p));
i64 m = (l+r)/2;
if(p < m){ i = i*2; r = m; }
else{ i = i*2+1; l = m; }
}
return res;
}
Func minFunc(i64 p){
int i = 1;
Func res = infFunc();
int l = 0, r = N;
while(i < V.size()){
if(!visited[i]) break;
if(V[i](p) < res(p)) res = V[i];
i64 m = (l+r)/2;
if(p < m){ i = i*2; r = m; }
else{ i = i*2+1; l = m; }
}
return res;
}
};
int main(){
ios::sync_with_stdio(false); cin.tie(nullptr);
i64 N, M; cin >> N >> M;
vector<pair<i64, i64>> A, B;
rep(i,N){
i64 a,d; cin >> a >> d;
if(d <= 0) B.push_back({ d, a });
else A.push_back({ d, a });
}
auto nthTerm = [](i64 d, i64 a, i64 n) -> i64 {
return a + d * n;
};
auto prefixSum = [](i64 d, i64 a, i64 n) -> i64 {
i64 ans = a * n;
ans += d * ((n*n-n)/2);
return ans;
};
vector<i64> valdown;
if(!B.empty()){
int n = B.size();
vector<int> ptr(n);
priority_queue<pair<i64, i64>> que;
rep(v,n){
auto [d,a] = B[v];
que.push({ nthTerm(d, a, ptr[v]), v });
}
rep(i,M){
auto [p,v] = que.top(); que.pop();
valdown.push_back(p);
ptr[v]++;
auto [d,a] = B[v];
que.push({ nthTerm(d, a, ptr[v]), v });
}
} else {
rep(v,M) valdown.push_back(-500000'0000000);
}
vector<i64> valup(M+1);
if(!A.empty()) {
LiChaoTree ds(M+1);
for(auto [d,a] : A){
LiChaoTree::Func f;
f.a = -d; f.b = -2*a+d;
ds.addLine(f);
}
for(int i=0; i<=M; i++){
i64 q = -ds.minVal(i);
valup[i] = q * i / 2;
}
} else {
rep(i,M) valup[i+1] = -INF;
}
vector<i64> valdownSum(M+1);
rep(i,M) valdownSum[i+1] = valdownSum[i] + valdown[i];
i64 ans = -INF;
rep(i,M+1) ans = max(ans, valdownSum[i] + valup[M-i]);
cout << ans << endl;
return 0;
}
Nachia