zoukankan      html  css  js  c++  java
  • 「HNOI2019」序列

    传送门

    Luogu

    题解

    终于看保序回归了吗

    首先送了( ext{50pts}),直接用保序回归例题1的做法即可。

    仔细分析一下,这个(B)就是(frac{sum A}{sum W}),那么我们考虑分成若干段之后的答案是:

    [egin{align} sum{(A_i-B)}^2&=sum A_i^2 + sum B^2- 2sum A_iB \ &=sum A_i^2+sum wfrac{sum A^2}{sum w^2}-2 imesfrac{sum A}{sum w} \ &=sum A_i^2 -frac{sum A^2}{sum w} end{align} ]

    所以只需要维护(sum A,sum w),前面这个(A_i^2)可以直接维护。

    const int N=200010,Mod=998244353;
    int n,m,A[N];
    int qpow(int a,int b){int ret=1;while(b){if(b&1)ret=1ll*ret*a%Mod;b>>=1;a=1ll*a*a%Mod;}return ret;}
    struct node
    {
    	ll x,y;
    	bool operator<(const node &b)const{return 1ll*x*b.y<1ll*y*b.x;}
    	node operator+(const node &b)const{return (node){x+b.x,y+b.y};}
    	int calc(){return 1ll*(x%Mod)*(x%Mod)%Mod*qpow(y%Mod,Mod-2)%Mod;}
    }sta[N];
    int calc()
    {
    	int ans=0,top=0;
    	for(int i=1;i<=n;i++)ans=(ans+1ll*A[i]*A[i]%Mod)%Mod;
    	for(int i=1;i<=n;i++)
    	{
    		node ret=(node){A[i],1};
    		while(top&&ret<sta[top]){ret=ret+sta[top];top--;}
    		sta[++top]=ret;
    	}
    	for(int i=1;i<=top;i++)ans=(ans-sta[i].calc()+Mod)%Mod;
    	return ans;
    }
    

    考虑(100pts),我们现在需要改变一个数字的值,然后维护这个栈。

    不难想到可以选择左边的一个栈位置,右边的一个栈位置((L0,R0)),然后合并成一段。

    那么考虑这个((L0,R0))的需求是合并成一段后对于前后都合法,这一段刚好可以合并成一段。

    也就是说对于一个(R0)我们要求一个最大的(L0),同时要求最大的(R0)

    所以我们可以二分(R0),然后二分(L0)即可。

    代码

    /*====================
    author: fexuile
    mail: fexuile@qq.com
    QQ: 2165008534
    ====================*/
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<queue>
    #include<iostream>
    #include<set>
    #include<map>
    using namespace std;
    #define mp make_pair
    #define ll long long
    #define re register
    typedef pair<int,int> pii;
    #define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
    inline int gi()
    {
    	int f=1,sum=0;char ch=getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return f*sum;
    }
    const int N=200010,Mod=998244353;
    int n,m,x[N];
    int qpow(int a,int b){int ret=1;while(b){if(b&1)ret=1ll*ret*a%Mod;b>>=1;a=1ll*a*a%Mod;}return ret;}
    struct node
    {
    	ll x,y;
    	bool operator<(const node &b)const{return 1ll*x*b.y<1ll*y*b.x;}
    	node operator+(const node &b)const{return (node){x+b.x,y+b.y};}
    	int calc(){return 1ll*(x%Mod)*(x%Mod)%Mod*qpow(y%Mod,Mod-2)%Mod;}
    }staA[N],staB[N];
    int sA[N],sB[N],topA,topB,A[N],B[N],ans[N],ql,qr;
    ll sum[N][2];
    vector<pii>vec[N];
    void getL(int delta,int R0)
    {
    	int l=0,r=topA;
    	while(l<r)
    	{
    		int mid=(l+r+1)>>1;
    		if(staA[mid]<((node){sum[R0-1][0]-sum[A[mid]][0]+delta,R0-A[mid]-1}))l=mid;
    		else r=mid-1;
    	}
    	ql=l;
    }
    void getR(int delta)
    {
    	int l=0,r=topB;
    	while(l<r)
    	{
    		int mid=(l+r+1)>>1;getL(delta,B[mid]);
    		if(((node){sum[B[mid]-1][0]-sum[A[ql]][0]+delta,B[mid]-A[ql]-1})<staB[mid])l=mid;
    		else r=mid-1;
    	}
    	qr=l;getL(delta,B[qr]);
    }
    int solve(int delta)
    {
    	getR(delta);
    //	printf("%d %d %d
    ",A[ql],B[qr],delta);
    	return ((ll)sA[ql]+sB[qr]+((node){sum[B[qr]-1][0]-sum[A[ql]][0]+delta,B[qr]-A[ql]-1}).calc())%Mod;
    }
    vector<int>del[N];
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("in.in","r",stdin);
    #endif
    	n=gi();m=gi();
    	for(int i=1;i<=n;i++)x[i]=gi(),sum[i][0]=sum[i-1][0]+x[i],sum[i][1]=(sum[i-1][1]+1ll*x[i]*x[i]%Mod)%Mod;
    	for(int i=1;i<=m;i++)
    	{
    		int p=gi();
    		vec[p].push_back(mp(gi()-x[p],i));
    	}
    	B[0]=n+1;
    	for(int i=n;i;i--)
    	{
    		node ret=(node){x[i],1};
    		while(topB&&staB[topB]<ret)
    		{
    			del[i].push_back(B[topB]);
    			ret=ret+staB[topB];topB--;
    		}
    		staB[++topB]=ret;sB[topB]=(sB[topB-1]+ret.calc())%Mod;B[topB]=i;
    	}
    	printf("%d
    ",(sum[n][1]-sB[topB]+Mod)%Mod);
    	for(int i=1;i<=n;i++)
    	{
    		topB--;
    		for(int j=del[i].size()-1;~j;j--)
    		{
    			B[++topB]=del[i][j];
    			staB[topB]=(node){sum[B[topB-1]-1][0]-sum[B[topB]-1][0],B[topB-1]-B[topB]};
    			sB[topB]=(sB[topB-1]+staB[topB].calc())%Mod;
    		}
    		
    		int res=(sum[n][1]-1ll*x[i]*x[i]%Mod+Mod)%Mod;
    		for(auto id:vec[i])
    			ans[id.second]=((res+1ll*(x[i]+id.first)*(x[i]+id.first)%Mod)%Mod-solve(id.first)+Mod)%Mod;
    		
    		node ret=(node){x[i],1};
    		while(topA&&ret<staA[topA]){ret=ret+staA[topA];topA--;}
    		staA[++topA]=ret;sA[topA]=(sA[topA-1]+ret.calc())%Mod;A[topA]=i;
    	}
    	for(int i=1;i<=m;i++)printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    XML解析
    资源管理
    Android中的动态字符串的处理
    消息提示的三种方式
    程序调控和监视(Logcat,Debug)
    选择改变事件OnCheckedChange
    递归和非递归分别实现求n的阶乘
    递归和非递归分别实现strlen
    编写一个函数 reverse_string(char * string)实现:将参数字符串中的字符反向排列 。(递归实现)
    写一个递归函数DigitSum(n),输入一个非负整数,返回组成它的数字之和
  • 原文地址:https://www.cnblogs.com/fexuile/p/13197218.html
Copyright © 2011-2022 走看看