把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【CF1750F】Majority(容斥+DP)

题目链接

  • 规定一个 \(01\)\(s\) 是好的,当且仅当可以经过若干次下面的操作将它变成全 \(1\):选择一对 \(i,j\) 满足 \(s_i=s_j=1\)\(\sum_{k=i}^js_k\ge\frac{j-i+1}2\),将 \(s_{i\sim j}\) 全部修改为 \(1\)
  • 求有多少个长度为 \(n\)\(01\) 串是好的。
  • \(1\le n\le5\times10^3\)

考虑最终状态

容易发现无论如何操作一个串,它所能达到的最终状态是一定的。

一个串无法继续操作的充要条件就是相邻两段 \(1\) 的长度之和小于它们之间的 \(0\) 的长度。

所以考虑直接根据这个最终状态来 DP。

容斥+DP

\(f_{i,j}\) 表示长度为 \(i\)、满足两端都是 \(1\) 且最后一段 \(1\) 长度为 \(j\) 的最终状态数。

则长度为 \(i\) 的好串数就是 \(f_{i,j}\)。显然可以容斥计算出 \(f_{i,i}=2^{i-2}-\sum_{j=1}^{i-1}f_{i,j}\)(特殊地,\(f_{1,1}=1\))。

对于 \(j < i\)\(f_{i,j}\),设最后一段 \(0\) 的长度为 \(k\),则可以从满足 \(x+j < k\)\(f_{i-j-k,x}\) 转移,变形一下就是 \((i-j-k)+x < i-2j\)

于是设 \(g_t\)\(i+j\le t\)\(f_{i,j}\) 之和,可知 \(f_{i,j}=g_{i-2j-1}\times f_{j,j}\)

代码:\(O(n^2)\)

#include<bits/stdc++.h>
#define Cn const
#define CI Cn int&
#define N 5000
#define Inc(x,y) ((x+=(y))>=X&&(x-=X))
#define Dec(x,y) ((x-=(y))<0&&(x+=X))
using namespace std;
int n,X,f[N+5][N+5],g[N+5],d[N+5];
int main()
{
	int i;for(scanf("%d%d",&n,&X),f[1][1]=1,i=2;i<=n;++i) g[i]=1;//f[1][1]=1
	int j,t=0,p=1;for(i=2;i<=n;++i)//容斥+DP
	{
		for(j=1;j^i;++j) i-2*j>0&&(f[i][j]=1LL*g[i-2*j-1]*f[j][j]%X);//转移j<i的f[i][j]
		for(f[i][i]=p,j=1;j^i;++j) Dec(f[i][i],f[i][j]);p=(p<<1)%X;//容斥f[i][i]
		for(t=0,j=1;i+j<=n;++j) Inc(t,f[i][j]),Inc(g[i+j],t);//更新g
	}
	return printf("%d\n",f[n][n]),0;
}
posted @ 2022-11-14 18:20  TheLostWeak  阅读(185)  评论(0编辑  收藏  举报