AtCoder Regular Contest 115 E. LEQ and NEQ(容斥 单调栈优化dp)

题目

n(n<=5e5)个数,第i个数ai(1<=ai<=1e9)

构造一个序列b,要求bi∈[1,ai],且b[i]不等于b[i+1]

求方案数,答案对998244353取模

思路来源

洛谷题解Xu_brezza

一模一样的cf题:

Codeforces Round 759 (Div. 2, based on Technocup 2022 Elimination Round 3) F. Non-equal Neighbours

题解

首先肯定是容斥,假设出现了一对冲突的就叫有一个坏点,

那么,答案=没有冲突的-至少一个冲突的+至少两个冲突的...

出现了一个坏点,就认为是合并减少了一个数,

所以最后如果减少了k个数,就认为序列被拆成了n-k段,且每段内的数字相同

dp[i][j]表示前i个数被划分成了j段的方案数,

其中每段内的数字是相同的,也就是从[1,这一段的最小值]中取

1. 朴素转移即枚举最后一段在哪,补上这最后一段的贡献,对应了这一个区间的最小值

dp[i][j]+=\sum_{k=0}^{i-1}dp[k][j-1]*min_{x=k+1}^i{a_{x}}

复杂度O(n^3)

2. 注意到,第二维对容斥系数的贡献,只有第二维的奇偶性,所以可以改写为

dp[i][j\&1]+=\sum_{k=0}^{i-1}dp[k][j\&1\bigoplus 1]*min_{x=k+1}^i{a_{x}}

前缀和分别维护第二维为奇数/为偶数的和,

复杂度O(n^2)

3. 单调栈优化,注意到,如果找到了前面第一个小于ai的数是p,

那么,ai对前面的位置的数,也就是k<p的位置不再有贡献,

考虑k<p的位置的和,

\sum_{k=0}^{p-1}dp[k][j\&1\bigoplus 1]*min_{x=k+1}^i{a_{x}}

=\sum_{k=0}^{p-1}dp[k][j\&1\bigoplus 1]*min_{x=k+1}^p{a_{x}}

=dp[p][j\&1]

所以有,

dp[i][j\&1]+=dp[p][j\&1]+\sum_{k=p}^{i-1}dp[k][j\&1\bigoplus 1]*a[i]

那么,一边维护单调栈一边维护前缀和即可,

特别地,如果不存在这样的p,说明ai是前缀最小,

观察原式后代入ai,有dp[i][j\&1]+=\sum_{k=0}^{i-1}dp[k][j\&1\bigoplus 1]*a[i]

前0个数分成偶数段方案数为1,分成奇数段方案数为0,对应dp[0][0]=1

最后,答案=\sum至少出现偶数次冲突-\sum至少出现奇数次冲突方案

如果n为偶数,说明分成偶数段=出现偶数次冲突,答案是dp[n][0]-dp[n][1]

否则,如果n为奇数,说明分成奇数段=出现偶数次冲突,答案是dp[n][1]-dp[n][0]

复杂度O(n)

代码1

#include<iostream>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair<int,int> P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<<x<<" ";
#define dbg2(x) cerr<<(#x)<<":"<<x<<endl;
#define SZ(a) (int)(a.size())
#define sci(a) scanf("%d",&(a))
#define scll(a) scanf("%lld",&(a))
#define pt(a) printf("%d",a);
#define pte(a) printf("%d\n",a)
#define ptlle(a) printf("%lld\n",a)
#define debug(...) fprintf(stderr, __VA_ARGS__)
const int N=5e5+10,mod=998244353;
int n,a[N],dp[N][2],sum[N][2],stk[N],c,ans;
// dp[i][j&1]+=dp[p][j&1]+sum dp[k][j&1^1]*a[i],p为小于ai的最大位置
void add(int &x,int y){x=(x+y)%mod;
}
int cal(int l,int r,int v){if(l==0)return sum[r][v];return (sum[r][v]-sum[l-1][v]+mod)%mod;
}
int main(){sci(n);dp[0][0]=sum[0][0]=1;rep(i,1,n){sci(a[i]);while(c && a[stk[c]]>=a[i]){c--;}rep(j,0,1){if(c)dp[i][j]=(dp[stk[c]][j]+1ll*cal(stk[c],i-1,j^1)*a[i]%mod)%mod;else dp[i][j]=1ll*cal(0,i-1,j^1)*a[i]%mod;sum[i][j]=(sum[i-1][j]+dp[i][j])%mod;}stk[++c]=i;//printf("i:%d dp:(%d,%d)\n",i,dp[i][0],dp[i][1]);}if(n&1)ans=(dp[n][1]-dp[n][0]+mod)%mod;else ans=(dp[n][0]-dp[n][1]+mod)%mod;printf("%d\n",ans);return 0;
}

代码2

自己的乱搞,基于以下这个式子,构造单调栈优化

其中,dp[i]表示以i结尾的方案数,枚举最后一段合并了几个数,

假设最后一段x个数,说明冲突了x-1次,容斥系数是(-1)的x-1次方,加上对应的贡献即可

dp[i]+=dp[j]*min_{x=j+1}^{i}a_{x}*(-1)^{i-j-1}, j<i

#include<iostream>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair<int,int> P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<<x<<" ";
#define dbg2(x) cerr<<(#x)<<":"<<x<<endl;
#define SZ(a) (int)(a.size())
#define sci(a) scanf("%d",&(a))
#define scll(a) scanf("%lld",&(a))
#define pt(a) printf("%d",a);
#define pte(a) printf("%d\n",a)
#define ptlle(a) printf("%lld\n",a)
#define debug(...) fprintf(stderr, __VA_ARGS__)
const int N=5e5+10,mod=998244353;
//dp[i]+=dp[j]*min(a[j+1],...,a[i])*(-1)^(i-j-1),j<i
//dp[1]+=dp[0]*a[1]
//dp[2]+=dp[1]*a[2]
//dp[2]-=dp[0]*min(a[1],a[2])
int n,a[N],dp[N],sum[2],sum2[N],stk[N],mn[N],cp[N][2],c;
void add(int &x,int y){x=(x+y)%mod;
}
int main(){sci(n);rep(i,1,n){sci(a[i]);if(i==1)mn[i]=a[i];else mn[i]=min(mn[i-1],a[i]);}rep(i,0,n){while(c && a[stk[c]]>=a[i]){int p=stk[c],x=(p-1)&1;add(sum[x],mod-1ll*cp[p-1][0]*a[p]%mod);//jadd(sum2[x],cp[p-1][0]);//jadd(sum[x^1],mod-1ll*cp[p-1][1]*a[p]%mod);//jadd(sum2[x^1],cp[p-1][1]);//jc--;}//1 2 4 6 5 7//printf("i:%d sum:(%d,%d) sum2:(%d,%d)\n",i,sum[0],sum[1],sum2[0],sum2[1]);int v1=(sum[i&1^1]-sum[i&1]+mod)%mod;int v2=1ll*(sum2[i&1^1]-sum2[i&1]+mod)*a[i]%mod;dp[i]=(v1+v2)%mod;if(i&1)add(dp[i],mn[i]);//dp[0]的贡献else add(dp[i],mod-mn[i]);//printf("i:%d dp:%d\n",i,dp[i]);int x=(i-1)&1;stk[++c]=i;cp[i-1][0]=sum2[x];cp[i-1][1]=sum2[x^1];add(sum[x],1ll*cp[i-1][0]*a[i]%mod);add(sum[x^1],1ll*cp[i-1][1]*a[i]%mod);sum2[0]=sum2[1]=0;while(c && a[stk[c]]>=a[i+1]){int p=stk[c],x=(p-1)&1;add(sum[x],mod-1ll*cp[p-1][0]*a[p]%mod);//jadd(sum2[x],cp[p-1][0]);//jadd(sum[x^1],mod-1ll*cp[p-1][1]*a[p]%mod);//jadd(sum2[x^1],cp[p-1][1]);//jc--;}stk[++c]=i+1;x=i&1;cp[i][0]=(sum2[x]+dp[i])%mod;cp[i][1]=sum2[x^1];sum2[0]=sum2[1]=0;add(sum[x],1ll*cp[i][0]*a[i+1]%mod);add(sum[x^1],1ll*cp[i][1]*a[i+1]%mod);}printf("%d\n",dp[n]);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/417671.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解析智能酒精壁炉不完全燃烧的成因及潜在问题

解析智能酒精壁炉不完全燃烧的成因及潜在问题 智能酒精壁炉作为一种环保、高效、现代化的取暖工具&#xff0c;其采用酒精作为燃料进行燃烧&#xff0c;但在一些情况下&#xff0c;可能会出现酒精燃烧不完全的问题。下面将深入探讨这一现象的成因以及可能引发的问题。 成因分析…

php isset和array_key_exists区别

在PHP中&#xff0c;可以使用array_key_exists函数或者isset函数来判断一个字典&#xff08;关联数组&#xff09;中是否存在某个下标。 使用 array_key_exists 函数: $myArray array("key1" > "value1", "key2" > "value2",…

基于动态顺序表实现通讯录项目

本文中&#xff0c;我们将使用顺序表的结构来完成通讯录的实现。 我们都知道&#xff0c;顺序表实际上就是一个数组。而使用顺序表来实现通讯录&#xff0c;其内核是将顺序表中存放的数据类型改为结构体&#xff0c;将联系人的信息存放到结构体中&#xff0c;通过对顺序表的操…

【数据结构与算法】1.时间复杂度和空间复杂度

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ &#x1f64f;小杨水平有限&#xff0c;欢迎各位大佬指点&…

架构的演进

1.1单体架构 单体架构也称之为单体系统或者是单体应用。就是一种把系统中所有的功能、模块耦合在一个应用中的架构方式。 存在的问题&#xff1a; 代码耦合&#xff1a;模块的边界模糊、依赖关系不清晰&#xff0c;整个项目非常复杂&#xff0c;每次修改代码都心惊胆战迭代困…

linux基础学习(5):yum

yum是为了解决rpm包安装依赖性而产生的一种安装工具 1.yum源 1.1配置文件位置 yum源的配置文件在/etc/yum.repos.d/中 *Base源是网络yum源&#xff0c;也就是需要联网才能使用的yum源。默认情况下&#xff0c;系统会使用Base源 *Media源是光盘yum源&#xff0c;是本地yum源…

论文阅读笔记AI篇 —— Transformer模型理论+实战 (三)

论文阅读笔记AI篇 —— Transformer模型理论实战 &#xff08;三&#xff09; 第三遍阅读&#xff08;精读&#xff09;3.1 Attention和Self-Attention的区别&#xff1f;3.2 Transformer是如何进行堆叠的&#xff1f;3.3 如何理解Positional Encoding&#xff1f;3.x 文章涉及…

【数据结构】详谈队列的顺序存储及C语言实现

循环队列及其基本操作的C语言实现 前言一、队列的顺序存储1.1 队尾指针与队头指针1.2 基本操作实现的底层逻辑1.2.1 队列的创建与销毁1.2.2 队列的增加与删除1.2.3 队列的判空与判满1.2.4 逻辑的局限性 二、循环队列2.1 循环队列的实现逻辑一2.2 循环队列的实现逻辑二2.3 循环队…

CodeReview 小工具

大家开发中有没有遇到一个版本开发的非常杂&#xff0c;开发很多个项目&#xff0c;改动几周后甚至已经忘了自己改了些什么&#xff0c;领导要对代码review的时候&#xff0c;理不清楚自己改过的代码&#xff0c;只能将主要改动的大功能过一遍。这样就很容易造成review遗漏&…

软件测试(一)

软件测试——测试用例 &#x1f3d0;测试用例要素&#xff08;四个重要的要素&#xff09;&#x1f3d0;测试用例的设计方法&#x1f3c0;基于需求的设计方法&#x1f3c0;等价类&#x1f3c0;边界值&#x1f3c0;判定表&#x1f3c0;正交表法&#x1f3c0;场景设计法&#x1f…

Prompt高级技巧:Few-Shots、COT、SC、TOT、Step-Back

CRISPE框架 如图所示。所谓CRISPE框架&#xff0c;指的是&#xff1a; CR&#xff1a;Capacity and Role&#xff08;能力与角色&#xff09;。你希望 ChatGPT 扮演怎样的角色。I&#xff1a;Insight&#xff08;洞察&#xff09;&#xff0c;背景信息和上下文。S:&#xff08…

在IDEA上运行成功,打包成jar包后,运行报错,程序自动退出

原因 java环境不正确&#xff0c;很有可能安装了多个环境&#xff0c;导致程序加载了错误程序。 解决办法 尝试修改环境变量&#xff0c;如果不行&#xff0c;建议删除掉多余的java环境。 注意&#xff1a;删除掉多余的Java环境需要用程序删除&#xff0c;直接删除文件&#xf…