zoukankan      html  css  js  c++  java
  • uoj213 【UNR #1】争夺圣杯

    题目

    (f_i)表示所有长度为(i)的区间的最大值的和,求(igoplus sum_{i=1}^nf_i)

    不难发现随机数据非常好做

    由于一个随机序列的前缀最大值期望只会变化(log)次,所以完全可以从这个条件上入手

    考虑维护一个合并式单调栈,每次插入一个数之后,单调栈中存在的都是当前这个前缀所有的后缀最大值,我们直接暴力扫一遍这些后缀最大值,于是有一些针对(f)数组的区间加,我们直接差分维护就好了

    这样在数据随机意义下是(O(nlog n))的,一发跑过了除了( m hack)数据以外的所有数据也是非常惊人

    考虑正解,使用单调栈找到一个位置(i)左边第一个小于等于他的(j),和右边第一个大于他的(k),显然在左端点在([j,i])内,右端点在([i,k))的区间的最大值都是(a_i),于是直接讨论一下(a_i)对这些长度区间的贡献就好了

    (a=min(i-j+1,k-i),b=max(i-j+1,k-i))

    对于长度为([1,a])的区间,贡献是(x imes a_i)

    对于长度为([a+1,b])的区间,贡献是(b imes a_i)

    对于长度为([b+1,a+b-1])的区间,贡献为((b-x) imes a_i=b imes a_i-x imes a_i)

    维护两个差分数组,一个用于维护这个位置实际上增加了多少,一个用于维护这个位置增加了多少倍的(x)

    随便就做完了,复杂度是(O(n))

    代码

    #include<bits/stdc++.h>
    #define re register
    #define LL long long
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    const int mod=998244353;
    const int maxn=1e6+5;
    int a[maxn],pre[maxn],mn[maxn],t[maxn],st[maxn],c[maxn];
    int n,top;LL ans;
    inline void calc(int pos) {
    	int a=t[top]-mn[top]+1,b=pos-t[top]+1;
    	if(a>b) std::swap(a,b);
    	int v=st[top]%mod;
    	if(a<b) {
    		pre[a+1]=(pre[a+1]+1ll*a*v%mod)%mod;
    		pre[b+1]=(pre[b+1]-1ll*a*v%mod+mod)%mod;
    	}
    	c[1]=(c[1]+v)%mod,c[a+1]=(c[a+1]-v+mod)%mod;
    	if(b<a+b-1) {
    		c[b+1]=(c[b+1]-v+mod)%mod,c[a+b]=(c[a+b]+v)%mod;
    		pre[b+1]=(pre[b+1]+1ll*(a+b)*v%mod)%mod;
    		pre[a+b]=(pre[a+b]-1ll*(a+b)*v%mod+mod)%mod;
    	}
    }
    int main() {
    	n=read();for(re int i=1;i<=n;++i) a[i]=read();top=0;
    	for(re int i=1;i<=n;i++) {
    		int now=i;
    		while(top&&a[i]>=st[top]) calc(i-1),now=mn[top],top--;
    		mn[++top]=now,t[top]=i,st[top]=a[i];
    	}
    	while(top) calc(n),top--;
    	for(re int i=1;i<=n;i++) pre[i]=(pre[i-1]+pre[i])%mod;
    	for(re int i=1;i<=n;i++) c[i]=(c[i-1]+c[i])%mod;
    	for(re int i=1;i<=n;i++) 
    		pre[i]=(pre[i]+1ll*c[i]*i%mod)%mod,ans^=pre[i];
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    一、HTML基础学习
    算法之求正整数的二进制
    JavaScript ajax返回状态
    ajax实现异步校验
    比较喜欢的一种求阶乘的方法:用递归求阶乘
    java中自定义异常类
    我对多态的理解
    包装类和基本类型区别?(integer和int取值范围一样大)
    JAVA中默认的编码方式
    抽象类和接口的区别
  • 原文地址:https://www.cnblogs.com/asuldb/p/11414455.html
Copyright © 2011-2022 走看看