[atAGC055D]ABC Ultimatum

记$f_{k}$为$\max_{0\le i\le 3n}\sum_{j=1}^{i}([s_{j}=next(k)]-[s_{j}=k])$(其中$k\in \{a,b,c\},next(a/b/c)=b/c/a$)

结论:有解当且仅当$\sum_{k\in \{a,b,c\}}f_{k}\le n$

必要性:对于合法的子序列,都包含两个形如$(k,next_{k})$的顺序对(每一个字符最多使用一次)

而考虑$f_{a}$,即意味着$(a,b)$这样的顺序对至多只会出现$n-f(a)$次(在$i$之前的多出的$b$一定无法使用),而总共要有$2n$个,代入后也即$\sum_{k\in \{a,b,c\}}f_{k}\le n$

充分性:将第$i$个a、第$i+f_{a}$个b和第$i+f_{a}+f_{b}$个c组成一个子序列(后两者若大于$n$再减去$n$)

性质:$\forall k\in \{a,b,c\},i+f_{k}\le n$,第$i$个$k$总是在第$i+f_{k}$个$next(k)$之前

考虑第$i$个$k$的前缀(不包括第$i$个$k$),其中有$i+f_{k}$个$next(k)$和$i-1$个$k$,与$f_{k}$最大性矛盾

由此,对$i$分类讨论,来证明$i$时的子序列合法:

1.若$i+f_{a}+f_{b}\le n$,由性质显然这是一个形如abc的子序列

2.若$i+f_{a}\le n<i+f_{a}+f_{b}$,后者结合条件即$i>f_{c}$且$i+f_{a}+f_{b}-n<i-f_{c}$,由性质显然这是一个形如cab的子序列

3.若$n<i+f_{a}$,类似地上述两种情况,也可以证明这是一个形如bca的子序列

综上,即得证

由此,对每一个$k$的当前前缀和和最大前缀和(即$f_{k}$)一起dp即可,时间复杂度为$o(n^{7})$

另一方面,注意到当前前缀和之和必然为0,即可优化到$o(n^{6})$

总复杂度为$o(n^{6})$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 16
 4 #define mod 998244353
 5 int n,l,ans,f[N*3][N*2][N*2][N][N][N];
 6 char s[N*3];
 7 void Add(int &x,int y){
 8     x=(x+y<mod ? x+y : x+y-mod);
 9 }
10 int main(){
11     scanf("%d%s",&n,s),l=n*3;
12     f[0][n][n][0][0][0]=1;
13     for(int i=0;i<l;i++)
14         for(int sa=-n;sa<=n;sa++)
15             for(int sb=-n;sb<=n;sb++){
16                 int sc=-sa-sb;
17                 if (abs(sc)>n)continue;
18                 for(int fa=0;fa<=n;fa++)
19                     for(int fb=0;fb<=n;fb++)
20                         for(int fc=0;fc<=n;fc++){
21                             if (((s[i]=='A')||(s[i]=='?'))&&(sa>-n))
22                                 Add(f[i+1][sa+n-1][sb+n][fa][fb][max(fc,sc+1)],f[i][sa+n][sb+n][fa][fb][fc]);
23                             if (((s[i]=='B')||(s[i]=='?'))&&(sb>-n))
24                                 Add(f[i+1][sa+n+1][sb+n-1][max(fa,sa+1)][fb][fc],f[i][sa+n][sb+n][fa][fb][fc]);
25                             if (((s[i]=='C')||(s[i]=='?'))&&(sc>-n))
26                                 Add(f[i+1][sa+n][sb+n+1][fa][max(fb,sb+1)][fc],f[i][sa+n][sb+n][fa][fb][fc]);
27                         }
28             }
29     for(int fa=0;fa<=n;fa++)
30         for(int fb=0;fb<=n;fb++)
31             for(int fc=0;fc<=n;fc++)
32                 if (fa+fb+fc<=n)Add(ans,f[l][n][n][fa][fb][fc]);
33     printf("%d\n",ans);
34     return 0;
35 }
View Code

 

posted @ 2021-12-01 14:23  PYWBKTDA  阅读(136)  评论(0编辑  收藏  举报