Particle

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

ARC 073 F (嘘解法)

想定解法は segment tree だが、O(N^2) の DP を、隣の状態より strict に良い状態だけを残すような枝刈りしても通る。

発見した中でのワーストケースでは、
与えられる点が、
200000, 1, 100000, 50000, 75000, ...
のときに、保持する必要がある状態数が 20 近くになる。

#define N 200010
ll n, q, c, x[N];
set<P> dp[2];

int main(){
	cin>>n>>q>>x[0]>>c;
	rep(i, q) cin>>x[i+1];
	dp[0].insert(P(c, 0));
	for(int i = 1; i <= q; i++){
		int t = i%2;
		dp[t].clear();
		for(auto p: dp[!t]){
			dp[t].insert(P(x[i-1], p.snd+abs(x[i]-p.fst)));
			dp[t].insert(P(p.fst, p.snd+abs(x[i]-x[i-1])));
		}
		{
			auto it = dp[t].begin(), it2 = it; ++it2;
			while(it2!=dp[t].end()){
				while(it2!=dp[t].end() && it->snd+abs(it->fst-it2->fst)<=it2->snd){
					dp[t].erase(it2);
					it2 = it;
					++it2;
				}
				++it;
				if(it2!=dp[t].end()) ++it2;
			}
		}
		{
			auto it = dp[t].end();
			if(it!=dp[t].begin()) --it;
			auto it2 = it;
			if(it!=dp[t].begin()) --it2;
			while(it!=dp[t].begin()){
				while(it!=dp[t].begin() && it->snd+abs(it->fst-it2->fst)<=it2->snd){
					dp[t].erase(it2);
					it2 = it;
					if(it2!=dp[t].begin()) --it2;
				}
				if(it!=dp[t].begin()){
					--it;
					if(it2!=dp[t].begin()) --it2;
				}
			}
		}
	}
	ll res = 1e17;
	for(auto p: dp[q%2]) res = min(res, p.snd);
	cout<<res<<endl;
	return 0;
}