CF1542D Priority Queue

分析

大佬们都说是显然题,套路题,可是我一开始连这是个 DP 都想不到qwq。

状态数量太多,要求的值是所有状态的和,那么可以尝试统计贡献。

\(b\)\(a\) 的子序列,说白了就是,对于每一个操作,都能选,或者不选。那么可以对于每一个元素计算能够让它保留到最后的方案数,从而统计贡献。

\(f(i,j)\) 为在当前基准的一个下标 \(p\) 之下,考虑了前 \(i\) 个操作,其中有 \(j\) 个元素小于 \(a_p\) 的方案数。

如果第 \(i\) 个操作是删除,那么由于选不选都可以,转移为 \[ f(i,j) = f(i-1,j) + f(i-1,j+1) \] 前者为不选,后者为选。

特别地,当 \(i < p\) 并且 \(j=0\) 时,要再加上 \(f(i-1,j)\), 一种表示一直过来都没选,这次选但是什么也不做。另一种是选了但是删没了。

当第 \(i\) 个操作是加入,那么也可以选或不选。

\(a_i < a_p\)\[ f(i,j) = f(i-1,j) + f(i-1,j-1) \]\(a_i > a_p\) 时,选不选都不会改变 \[ f(i,j)= f(i-1,j) + f(i-1,j) \] 特别的,如果 \(a_i = a_p\),那么当 \(i< p\) 时,放到第一种转移,当 \(i>p\) 时,放到第二种转移。

特别地,当 \(i=p\) 时,直接将 \(i-1\) 的状态转移到 \(i\),因为必须选择。

最后累加 \[ \sum_{i=0}^n f(n,i) \]

CODE

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=505, mod=998244353;
int n, a[N];
char s[N];
ll f[N][N], ans;
int main() {
	scanf("%d",&n);
	for(int i=1;i<=n;++i) {	
		scanf(" %c",&s[i]);
		if(s[i]=='-') a[i]=-1; else scanf("%d",&a[i]);
	}
	for(int p=1;p<=n;++p) {
		int x=a[p];
		if(!~x) continue;
		memset(f,0,sizeof(f));
		f[0][0]=1;
		for(int i=1;i<=n;++i) {
			if(p==i) { memcpy(f[i],f[i-1],sizeof(f[i])); continue; }
			for(int j=0;j<=n;++j) {
				if(!~a[i]) {
					f[i][j]=(f[i-1][j]+f[i-1][j+1])%mod;
					if(i<p&&!j) (f[i][j]+=f[i-1][j])%=mod;
				} else if(a[i]<x||((a[i]==x&&i<p))) {
					f[i][j]=f[i-1][j];
					if(j) (f[i][j]+=f[i-1][j-1])%=mod;
				} else f[i][j]=2*f[i-1][j]%mod;
			}
		}
		ll sum=0;
		for(int i=0;i<=n;++i) (sum+=f[n][i])%=mod;
		(ans+=sum*x%mod)%=mod;
	}
	printf("%lld\n",ans);
}

CF1542D Priority Queue
https://yozora0908.github.io/2022/cf1542d-solution/
作者
yozora0908
发布于
2022年7月9日
许可协议