[CF1178F1]Short Colorful Strip
题目
题解
题目所要求的是从小到大染色,我们不妨顺着这个顺序对方案数进行统计
设 \(f[l][r]\) 为区间 \([l,r]\) 目前颜色一致(不然无法进行染色),将 \([l,r]\) 染成目标状态的方案数,由于我们先染最小编号的颜色,不妨记最小颜色的编号为 \(p\),这个 \(p\) 可以预处理出来:
inline void Solve_p(){
int minn;
rep(i,1,n)rep(j,i,n){
minn=INF;
rep(k,i,j)if(c[k]<minn)
minn=c[k],p[i][j]=k;
}
}
枚举最小颜色填入的区间为 \([i,j]\),而最后位置 \(p\) 要和目标状态一致,即保持为最小的颜色,那么我们所枚举的这个 \([i,j]\) 一定要使 \(p\in [i,j]\),不然无法保证和目标状态一致。
而后,由于 \([l,p-1]\) 和 \([p+1,r]\) 都要染成其他的颜色,而我们目前已经将 \([i,j]\) 染成最小颜色,所以我们整理一下区间 \([l,r]\) 中有哪些区间同色,可以继续染色:\([i,j]\),\([l,i-1]\),\([j+1,r]\),而我们要保证点 \(p\) 不染成其他颜色,所以要将 \(p\) 从 \([i,j]\) 中去掉,那么就是以下四个区间:
\[[l,i-1],[i,p-1],[p+1,j],[j+1,r]
\]
由排列组合,我们最后的转移即为
\[f[l][r]=\sum_{i=l}^{p}\sum_{j=p}^{r}f[l][i-1]\times f[i][p-1]\times f[p+1][j]\times f[j+1][r]
\]
注:此处定义当 \(i>j\) 时,\(f[i][j]=1\)
显然这个做法是 \(\mathcal O(n^4)\) 的,考虑对转移进行变换
\[f[l][r]=\sum_{j=p}^{r}f[p+1][j]\times f[j+1][r]\times \left [\sum_{i=l}^{p}f[l][i-1]\times f[i][p-1] \right ]
\]
发现前一半和后一半独立,那么我们只需记 \(sum[l][r]=\sum_{i=l}^{p}f[l][i-1]\times f[i][p-1]\),显然这个 \(sum\) 可以 \(\mathcal O(n)\) 处理,那么转移为
\[f[l][r]=sum[l][r]\times\left [ \sum_{j=p}^{r}f[p+1][j]\times f[j+1][r]\right ]
\]
这个就可以 \(\mathcal O(n)\) 做了,总体即为 \(\mathcal O(n^3)\)
对于最开始的情况,所有点都是颜色 \(0\),故 dfs(1,n)
代码
#include<cstdio>
#include<cstring>
#define rep(i,__l,__r) for(signed i=(__l),i##_end_=(__r);i<=i##_end_;++i)
#define fep(i,__l,__r) for(signed i=(__l),i##_end_=(__r);i>=i##_end_;--i)
#define erep(i,u) for(signed i=tail[u],v=e[i].to;i;i=e[i].nxt,v=e[i].to)
#define writc(a,b) fwrit(a),putchar(b)
#define mp(a,b) make_pair(a,b)
#define ft first
#define sd second
typedef long long LL;
// typedef pair<int,int> pii;
typedef unsigned long long ull;
typedef unsigned uint;
#define Endl putchar('\n')
// #define int long long
// #define int unsigned
// #define int unsigned long long
#define cg (c=getchar())
template<class T>inline void read(T& x){
char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
if(f)x=-x;
}
template<class T>inline T read(const T sample){
T x=0;char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
return f?-x:x;
}
template<class T>void fwrit(const T x){//just short,int and long long
if(x<0)return (void)(putchar('-'),fwrit(-x));
if(x>9)fwrit(x/10);
putchar(x%10^48);
}
template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}
inline int gcd(const int a,const int b){return b?gcd(b,a%b):a;}
inline void getInv(int inv[],const int lim,const int MOD){
inv[0]=inv[1]=1;for(int i=2;i<=lim;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
}
inline LL mulMod(const LL a,const LL b,const LL mod){//long long multiplie_mod
return ((a*b-(LL)((long double)a/mod*b+1e-8)*mod)%mod+mod)%mod;
}
const int MAXN=500;
const int MOD=998244353;
const int INF=0x3f3f3f3f;
int n,m,c[MAXN+5];
int f[MAXN+5][MAXN+5];
int p[MAXN+5][MAXN+5];
inline void Init(){
n=read(1),m=read(1);
rep(i,1,n)c[i]=read(1);
}
inline void Solve_p(){
int minn;
rep(i,1,n)rep(j,i,n){
minn=INF;
rep(k,i,j)if(c[k]<minn)
minn=c[k],p[i][j]=k;
}
// rep(i,1,m)rep(j,i,n){
// printf("p[%d, %d] == %d\n",i,j,p[i][j]);
// }
}
int sum[MAXN+5][MAXN+5];
int Dfs(const int l,const int r){
// printf("Now l == %d, r == %d\n",l,r);
if(l>r)return 1;
if(f[l][r]!=-1)return f[l][r];
f[l][r]=0;
rep(i,l,p[l][r]){
sum[l][r]=sum[l][r]+1ll*Dfs(l,i-1)*Dfs(i,p[l][r]-1)%MOD;
if(sum[l][r]>=MOD)sum[l][r]-=MOD;
}
rep(j,p[l][r],r){
f[l][r]=f[l][r]+1ll*Dfs(p[l][r]+1,j)*Dfs(j+1,r)%MOD*sum[l][r]%MOD;
if(f[l][r]>=MOD)f[l][r]-=MOD;
}
return f[l][r];
}
signed main(){
Init();
Solve_p();
memset(f,-1,sizeof f);
writc(Dfs(1,n),'\n');
// rep(i,1,n)rep(j,i,n){
// printf("f[%d, %d] == %d\n",i,j,f[i][j]);
// }
return 0;
}