题解 [ARC132C] Almost Sorted

【洛谷专栏】

做这道题的时候注意到了同名题目 CF1730F Almost Sorted,没想到都是状压 DP。

题意

参见题意翻译

分析

\(d \le 5\) 的数据范围非常小,很容易想到状压。

\(f_{i,S}\) 表示前 \(i\) 个数 \([i-d,i+d]\) 的占用情况(不包含已经确定的)为 \(S\) 时的方案数。

如果第 \(i\) 个数已经确定,那么直接从 \(i-1\) 的状态进行转移。

否则就枚举每一个可能的位置,再从上一个进行转移即可。

因为不好描述具体实现就看代码吧,时间复杂度 \(O(nd2^d)\)

代码

//the code is from chenjh
#include<cstdio>
#include<cmath>
using namespace std;
const int mod=998244353;
int n,d,a[505],p[505];
int f[505][1<<11];
int main(){
	scanf("%d%d",&n,&d);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		if(~a[i]){
			p[a[i]]=i;
			if(abs(a[i]-i)>d) return puts("0"),0; //已经确定的不符合条件直接判无解。
		}
	}
	**f=1;
	for(int i=1,mS=1<<(d<<1|1);i<=n;i++)
		if(p[i])for(int S=0;S<mS;++S){
			bool fl=1;
			for(int j=-d;j<=d;j++)if((i+j<1||i+j>n||~a[i+j])&&((S>>(j+d))&1)){fl=0;break;}//判断是否有被占用的不合法位置。
			if(fl)
				f[i][S]=(f[i-1][(S<<1)&(mS-1)]+f[i-1][(S<<1|1)&(mS-1)]);//从上一个状态转移,有两种情况。
		}
		else for(int S=0;S<mS;++S){
			bool fl=1;
			for(int j=-d;j<=d;j++)if((i+j<1||i+j>n||~a[i+j])&&((S>>(j+d))&1)){fl=0;break;}
			if(fl)for(int j=-d;j<=d;j++)if((S>>(j+d))&1)
				f[i][S]=(f[i][S]+(long long)f[i-1][((S^(1<<(j+d)))<<1)&(mS-1)]+f[i-1][((S^(1<<(j+d)))<<1|1)&(mS-1)])%mod;
		}
	int ans=0;
	for(int S=0,mS=1<<(d<<1|1);S<mS;++S)ans=(ans+f[n][S])%mod;//将所有情况求和。
	printf("%d\n",ans);
	return 0;
}
posted @ 2025-02-09 20:05  Chen_Jinhui  阅读(33)  评论(0)    收藏  举报