ARC086 D : Non-decreasing(600)

作成日:2017.12.12
最終更新日:2017.12.12

問題概要

問題本文

 長さ$N$の数列$\{a\}$がある。 操作「$1$以上$N$以下の整数$x,y$を選び、$a_y$に$a_x$を加算する」を$2N$回以下行うことで数列$\{a\}$が広義単調増加するようにしたい。 そのような操作手順を1つ求めよ。
制約
$2 \leq N \leq 50$
$-10^6 \leq a_i \leq 10^6$

考え方

 $a_i$は負にもなり得るが、まずはすべて負でないとして考える。 2つの非負整数$s,t$において必ず$s < s+t$が成り立つから、$i$が小さいものから$a_{i+1}$に$a_i$を加算していけば条件を満たす。 逆を考えれば$a_i$がすべて正でない時にも条件を満たす数列を構成できることが分かる。 以上より、$a_i$をすべて非負または非正にできれば良いことが分かる。 そのためには絶対値が最大のものを取ってきてすべての要素に足せばよい。 この$a_i$の正負を揃えるために$N$回、その後に数列を広義単調増加にするために$(N-1)$回の操作が必要だが、これは問題の条件に反しない。

ソースコード

マクロ等はこちら

int N;
int a[55];
vector<P2> ans;

int main(){
	cin >> N;
	int mx = -12345678 , mn = 12345678;
	int s = -1 , t = -1;
	repp(i,0,N){
		cin >> a[i];
		if(a[i]>mx){
			mx = a[i];
			s = i;
		}
		if(a[i]<mn){
			mn = a[i];
			t = i;
		}
	}
	if(mx > -mn){
		repp(i,0,N) if(a[i] <= 0){
			ans.PB(MP(s,i));
			a[i] += a[s];
		}
		repp(i,1,N){
			if(a[i-1] > a[i]){
				ans.PB(MP(i-1,i));
				a[i] += a[i-1];
			}
		}
	} else {
		repp(i,0,N) if(a[i] >= 0){
			ans.PB(MP(t,i));
			a[i] += a[t];
		}
		repm(i,N-1,0){
			if(a[i-1] > a[i]){
				ans.PB(MP(i,i-1));
				a[i-1] += a[i];
			}
		}
	}
	cout << ans.size() << endl;
	for(auto z : ans) cout << z.first+1 << ' ' << z.second+1 << endl;
	return 0;
}

解法まとめ

 絶対値が大きいものが正であったら、すべての要素にそれを加えて非負にした後、数列の先頭から$a_i$に$a_{i-1}$を加えて広義単調増加数列にする。(21-30行)
 そうでない時、絶対値が最大のものをすべての要素に加えて非正にした後、数列の後ろから$a_{i-1}$に$a_i$を加えて広義単調増加数列にする。(32-41行)

ARC086の他の問題 C E F

自己紹介

プログラミングとか合成音声とか
詳しくはこちら
twitter

プライバシーポリシー

個人情報利用についてはこちら

最終更新日:2023.03.05

お問い合わせ

このページに関するお問い合わせはこちら

競技プログラミングMENU

問題を解くまでの道のり

その他

全体MENU

寄付モドキ

0冂から10000冂まで
詳しくはこちら