题解 铺设道路

传送门

能想到差分这题就差不多了……可惜我没想到

先维护出差分序列
于是每次操作可以将前面一个地方-1后面一个地方+1
整个序列的前缀和处处大于0且整个序列的前缀和为0
于是每个大于零的位置都需要 \(abs(dlt_i)\) 次操作才能变为零,于是操作次数可知
然后考虑最大/小体力消耗
首先所有 \(r-l+1\) 的和应该是不变的(就是面积)
于是让最长的段尽可能长/短
可以用双端队列维护所有差分序列 \(>0\) 的位置
每遇到一个 \(<0\) 的位置,就考虑选一个最远/近的位置来平衡它
正确性证明的话考虑临项交换
发现对于一个 \(+1+1-1-1\) 的情况,最大化最大的一定不劣
于是可以贪心

  • 给一个序列的子区间加减,最后还要全消成零,求方案数什么的先考虑一下差分
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 300010
#define ll long long
#define fir first
#define sec second
#define make make_pair
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;
int d[N];
const ll mod=1e9+7;
inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}

namespace task1{
	void solve() {
		printf("%d\n", d[1]);
		printf("%lld\n%lld\n", 1ll*n*n%mod*d[1]%mod, 1ll*n*n%mod*d[1]%mod);
		exit(0);
	}
}

namespace task2{
	int dlt[N];
	ll ans;
	void solve() {
		for (int i=1; i<=n; ++i) dlt[i]=d[i]-d[i-1];
		for (int i=1; i<=n; ++i) ans=(ans+1ll*(n-i+1)*(n-i+1)%mod*dlt[i]%mod)%mod;
		printf("%d\n", d[n]);
		printf("%lld\n%lld\n", ans, ans);
		exit(0);
	}
}

namespace task{
	int dlt[N];
	ll ans1, ans2, step;
	deque<pair<int, int>> q1, q2;
	void solve() {
		for (int i=1; i<=n+1; ++i) {
			dlt[i]=d[i]-d[i-1];
			if (dlt[i]>0) step+=dlt[i];
		}
		pair<int, int> t;
		for (int i=1; i<=n+1; ++i) {
			if (dlt[i]>0) q1.push_back(make(i, dlt[i])), q2.push_back(make(i, dlt[i]));
			else if (dlt[i]<0) {
				int tem;
				tem=-dlt[i];
				while (tem>0) {
					t=q1.front(); q1.pop_front();
					if (tem>=t.sec) ans1=(ans1+1ll*(i-t.fir)*(i-t.fir)%mod*t.sec%mod)%mod, tem-=t.sec;
					else {
						t.sec-=tem;
						ans1=(ans1+1ll*(i-t.fir)*(i-t.fir)%mod*tem%mod)%mod;
						q1.push_front(t);
						tem=0;
					}
				}
				tem=-dlt[i];
				while (tem>0) {
					t=q2.back(); q2.pop_back();
					if (tem>=t.sec) ans2=(ans2+1ll*(i-t.fir)*(i-t.fir)%mod*t.sec%mod)%mod, tem-=t.sec;
					else {
						t.sec-=tem;
						ans2=(ans2+1ll*(i-t.fir)*(i-t.fir)%mod*tem%mod)%mod;
						q2.push_back(t);
						tem=0;
					}
				}
			}
		}
		printf("%lld\n", step);
		printf("%lld\n%lld\n", ans2, ans1);
		exit(0);
	}
}

signed main()
{
	freopen("road.in", "r", stdin);
	freopen("road.out", "w", stdout);

	n=read();
	bool all_same=1, all_add=1;
	for (int i=1; i<=n; ++i) {
		d[i]=read();
		if (i>1 && d[i]!=d[i-1]) all_same=0;
		if (i>1 && d[i]<d[i-1]) all_add=0;
	}
	// if (all_same) task1::solve();
	// else if (all_add) task2::solve();
	task::solve();
	
	return 0;
}
posted @ 2021-10-26 16:37  Administrator-09  阅读(1)  评论(0编辑  收藏  举报