自明な上界を達成できるパターンだった!
問題概要
長さ の非負整数列 が与えられる。この数列はどの隣接する二項も値が異なる。
この数列をなるべく多くの 項の非負整数列へと分解せよ。分解とは
- 分解された各非負整数列の各項を足すと、もとの数列 に一致する
- どの分解された非負整数列も、隣接二項間の大小関係が、もとの数列 に一致する
という条件を満たすことを指す。
制約
考えたこと
サンプルを見てみる。 は、次の 2 つの整数列に分解できる。
3 つには分解できない。なぜならば、8 - 6 = 2 だからだ。もし 3 つに分解できたとすると、合計したときに、二項目と三項目との差が 3 以上にならなければならない。しかし なのでそれは不可能だ。以上から
より多く分解することはできない
ということがいえた。
は達成可能
逆に、 個に分解することは常に可能だ。それが示されれば、 個が最大値ということで確定する。
まずなるべく多く分解するためには、「各 をなるべく均等に 分割したい」という気持ちになる。そして余った分は上から配っていく感じで OK。
コード
#include <bits/stdc++.h> using namespace std; template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; } template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; } int main() { int N; string S; cin >> N >> S; vector<long long> x(N+1); for (int i = 0; i < N+1; ++i) cin >> x[i]; long long M = 1LL<<60; for (int i = 0; i < N; ++i) chmin(M, abs(x[i]-x[i+1])); vector<vector<long long>> res(M, vector<long long>(N+1)); for (int j = 0; j <= N; ++j) { long long r = x[j] % M; for (int i = 0; i < M; ++i) { res[i][j] = x[j] / M; if (i < r) ++res[i][j]; } } cout << M << endl; for (int i = 0; i < M; ++i) { for (int j = 0; j <= N; ++j) cout << res[i][j] << " "; cout << endl; } }