Particle

競技プログラミングについての雑記

AOJ 2312: Magical Girl Sayaka-chan

解法

音程の最小値と最大値の間は、単調にすべきである。(単調で無かったらswapしてよりよい状態にできる)
音程をソートして、最小値から考えることにする。常に、左が右に追加していけばよいが、実はgreedyでよいことが分かる。floor(スコアの和/L)の部分はどうにもならないので、スコア%Lだけを考えれば良い。スコア%Lの和がL以上になると余計に答えが大きくなってしまうので、できるだけ超えないようにしなければならない。スコアの和は順次計算すればよく、mod Lでのスコアの値が大きい方に追加して、mod Lでのスコアを更新すればよい。

コード

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;

ll tk(vector<ll> &ss, int a, int b){ // [a,b]
	return ss[b+1]-ss[a];
}

int main(){
	ll n, m, l;
	cin>>n>>m>>l;
	vector<ll> v(n), s(m);
	for(ll &x: v){
		cin>>x;
		x--;
	}
	for(ll &x: s)
		cin>>x;

	vector<ll> ss(m+1, 0);
	for(int i = 0; i < m; i++){
		ss[i+1] = ss[i]+s[i];
	}	
	sort(v.begin(), v.end());
	ll res = 0;
	ll an, bn;
	an = bn = s[v[0]];
	for(int i = 1; i < n-1; i++){
		ll diff = tk(ss, v[i-1]+1, v[i]);
		an += diff;
		bn += diff;
		ll &cn = an%l>bn%l?an:bn;
		res += cn/l;
		cn = s[v[i]];
	}
	ll diff = tk(ss, v[n-2]+1, v[n-1]);
	an += diff;
	bn += diff;
	res += an/l + bn/l;

	cout<<res<<endl;

	return 0;
}