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

CF1750F Majority

题面传送门

看到这个题目觉得非常神奇。

首先我们考虑设\(g_i\)表示\(i\)长度的答案,但是显然不好转移。

考虑容斥,用总方案数减去不能消成一个的方案数,这里的总方案数要求两端都是黑的,也就是\(2^{i-2}\)

考虑一个不能弄成全\(1\)的最终状态长什么样,应该是\(2n+1\)段,奇数段为黑,偶数段为白,且每个白段的长度都大于两侧的黑段长度之和。

为此可以设计一个dp:设\(f_{i,j,0}\)表示前面总共有\(i\)个,最后以黑段结尾,且黑段长度为\(j\)的方案数。\(f_{i,j,1}\)表示前面总共有\(i\)个,最后以白段结尾,且白段减前面的黑段长度为\(j\)的方案数。

可以发现转移的形式是前缀和,可以优化到\(O(n^2)\)

code:

#include<bits/stdc++.h>
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n))
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=5e3+5,M=100+5,K=(1<<10)+5,mod=1e9+7,Mod=mod-1;ll INF=1e18+7;const db eps=1e-5;mt19937 rnd(time(0));
int n,p;ll f[N][N][2],Po[N],g[N],Q[N][N][2];
int main(){
	freopen("1.in","r",stdin);
	int i,j,h;scanf("%d%d",&n,&p);for(Po[0]=i=1;i<=n;i++) Po[i]=Po[i-1]*2%p;
	for(i=1;i<=n;i++){g[i]=(i^1?Po[i-2]:1);
		for(j=1;j<i;j++){
			//for(h=j+1;h<=i-j;h++) f[i][j][0]=(f[i-j][h][1]*g[j]+f[i][j][0])%p;
			f[i][j][0]=g[j]*Q[i-j][j+1][1]%p;
		}
		for(j=1;j<i;j++){
			//for(h=j+1;h<=i;h++) f[i][j][1]=(f[i-h][h-j][0]+f[i][j][1])%p;
			f[i][j][1]=Q[i-(j+1)][1][0];
		}
		for(j=0;j<=i;j++) g[i]-=f[i][j][0];for(j=1;i-j>j;j++) f[i][i-2*j][1]+=g[j];g[i]=(g[i]%p+p)%p;
		for(j=i;j;j--) Q[i][j][1]=(Q[i][j+1][1]+f[i][j][1])%p,Q[i][j][0]=(Q[i-1][j+1][0]+f[i][j][0])%p;
	}printf("%lld\n",g[n]);
}
posted @ 2022-11-14 17:27  275307894a  阅读(44)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end