namomo OJ contest2 C.序列

https://namomo.top:8081/contest/2/problem/C

妙啊,學到許多

首先最大的很好想,就是要儘可能長即可,那麼就用單調棧處理出每個值作爲最小值統治的區間,然後用線段樹維護這個位置還剩多少個需要減就行了。。。其實這個就是我當時坐積木大賽的貪心做法,儘可能長

最小從羣友那裏學到了,把整個序列差分,那麼我要讓一段區間減1,就相當於在差分數組上左邊+1,右邊-1,那麼對於差分數組中每個正數,都要找負數把它抵消掉,爲了要平方最小,那麼找最近的就好了,把負數座標反着用個棧維護,對每個正數找最近的負數去抵消就行了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxl=5e5+10;
const int mod=1e9+7;

int n,m,cas,k,cnt,tot,ans,top;
int a[maxl],b[maxl],s[maxl],l[maxl],r[maxl];
struct nod
{
	int val,id;
}c[maxl];
bool in[maxl]; 
ll ansmi,ansmx;
struct node
{
	int l,r,tag,val;
}tree[maxl<<2];

inline bool cmp(const nod &a,const nod &b)
{
	if(a.val==b.val)
		return a.id<b.id;
	return a.val<b.val;
}

inline void prework()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]),b[i]=a[i]-a[i-1];
		c[i]=nod{a[i],i};
	}
	b[n+1]=-a[n];
	sort(c+1,c+1+n,cmp);
} 

inline ll sqr(ll x)
{
	return x*x%mod;
}

inline void build(int k,int l,int r)
{
	tree[k].l=l;tree[k].r=r;
	if(l==r)
	{
		tree[k].val=a[l];
		return;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
}

inline void gank(int k)
{
	if(tree[k].l==tree[k].r)
		return;
	int x=tree[k].tag;
	tree[k<<1].val-=x;tree[k<<1].tag+=x;
	tree[k<<1|1].val-=x;tree[k<<1|1].tag+=x;
	tree[k].tag=0;
}

inline void upd(int k,int l,int r,int x)
{
	gank(k);
	if(tree[k].l==l && tree[k].r==r)
	{
		tree[k].val-=x;tree[k].tag+=x;
		return;
	}
	int mid=(tree[k].l+tree[k].r)>>1;
	if(r<=mid)
		upd(k<<1,l,r,x);
	else if(l>mid)
		upd(k<<1|1,l,r,x);
	else
	 	upd(k<<1,l,mid,x),upd(k<<1|1,mid+1,r,x);
}

inline int getnum(int k,int l)
{
	gank(k);
	if(tree[k].l==tree[k].r)
		return tree[k].val;
	int mid=(tree[k].l+tree[k].r)>>1;
	if(l<=mid)
		return getnum(k<<1,l);
	else
		return getnum(k<<1|1,l);
}

inline void mainwork()
{
	ansmi=0;
	for(int i=n+1;i>=1;i--)
	if(b[i]<0)
		s[++top]=i;
	for(int i=1;i<=n;i++)
	if(b[i]>0)
	{
		while(b[i]>0)
		{
			if(-b[s[top]]>b[i])
			{
				ansmi=(ansmi+sqr(s[top]-i)*b[i]%mod)%mod;
				b[s[top]]+=b[i];b[i]=0;
				break;
			}
			else
			{
				ansmi=(ansmi+sqr(s[top]-i)*(-b[s[top]])%mod)%mod;
				b[i]+=b[s[top]];b[s[top]]=0;
				top--;
			}
		}
	}
	top=0;a[0]=-1;s[0]=0;
	for(int i=1;i<=n;i++)
	{
		while(a[i]<=a[s[top]])
			top--;
		l[i]=s[top]+1;
		s[++top]=i;
	}
	top=0;a[n+1]=-1;s[0]=n+1;
	for(int i=n;i>=1;i--)
	{
		while(a[i]<=a[s[top]])
			top--;
		r[i]=s[top]-1;
		s[++top]=i;
	}
	build(1,1,n);int x,id;
	for(int i=1;i<=n;i++)
	{
		id=c[i].id;x=getnum(1,id);
		ansmx=(ansmx+x*sqr(r[id]-l[id]+1)%mod)%mod;
		upd(1,l[id],r[id],x);
	}
}

inline void print()
{
	printf("%lld %lld",ansmi,ansmx);
}

int main()
{
	int t=1;
	//scanf("%d",&t);
	for(cas=1;cas<=t;cas++)
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章