ARC115 E 题解
这个题目一开始就想到了容斥,不过我想到的容斥复杂度太大,并且没有进行进一步优化。
事后想了一种思路,即我们可以把钦定有 对相邻相等的方案数计算出来,运用线性 dp 就可以办到。
还有一种容斥思路是我们考虑后缀有多少相邻相等的,进行容斥。先上式子:
我们考虑一下这个式子为什么是正确的。
不难发现,如果我们想要计算 的话,其一定包含在 里面,但是可能会出现相邻两个重复。
我们考虑减掉,如果我们钦定其一定会出现相邻两个重复的话,一定也会出现相邻三个重复,一次类推。
更重要的是,如果在我们钦定一定会出现相邻两个重复的情况下,如果没有出现相邻三个重复,那么这种方案一定是在我们上面的那个 里面,这是因为如果没有出现相邻三个重复,前 个一定是一个合法序列。
由此可以知道容斥的正确性。
看到一句话,说容斥其实是在混合物中除杂,每次都会引入新的杂质,但要保证一定要去掉。
如果容斥可以用集合的形式表示出来,满足基本容斥的定义,那么这个容斥就是正确的,像上面,例如我们钦定相邻两个重复,它的集合就是所有两个重复和所有三个重复的并集。如果发现了这个性质,不难得到结果。
最上面那个式子可以选择用单调栈或线段树优化。
代码:
#include<bits/stdc++.h>
#define dd double
#define ld long double
#define int long long
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N 500010
#define M number
using namespace std;
const int INF=0x3f3f3f3f;
const int mod=998244353;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
int f[N],n,a[N];
typedef pair<int,int> P;
P Stack[N];int top,now,sg=1;
inline int sgn(int x){if(x&1) return -1;else return 1;}
signed main(){
// freopen("my.in","r",stdin);
// freopen("my.out","w",stdout);
read(n);for(int i=1;i<=n;i++) read(a[i]);
f[0]=1;
for(int i=1;i<=n;i++){
// printf("i=%d\n",i);
int sum=0;
while(top>0&&Stack[top].first>=a[i]){
(now-=1ll*Stack[top].second*Stack[top].first%mod)%=mod;
(sum+=Stack[top].second)%=mod;top--;
}
// printf("now=%d sum=%d\n",now,sum);
Stack[++top]=make_pair(a[i],(sum+sg*f[i-1])%mod);
(now+=1ll*Stack[top].first*Stack[top].second%mod)%=mod;
// printf("now=%d\n",now);
f[i]=1ll*now*sg%mod;sg*=(-1);
// printf("f[%d]=%d\n",i,f[i]);
}
printf("%lld\n",(f[n]%mod+mod)%mod);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
2020-01-22 STL deque 代码