[atAGC048F]01 Record

先将这个序列翻转,贪心找到最长的'101010……'的形式的子序列并删除,重复此过程并记这些字符串长度依次为$l_{1},l_{2},...,l_{n}$,若最终还有字符剩余则一定无解

假设$S$中元素从大到小依次为$x_{1},x_{2},...,x_{m}$,则合法当且仅当:

1.$L=\sum_{i=1}^{n}l_{i}=\sum_{i=1}^{m}x_{i}$

2.$\forall 1\le i\le n,\sum_{j=1}^{i}\lfloor \frac{l_{j}}{2}\rfloor\ge \sum_{j=1}^{i}\lfloor \frac{x_{j}}{2}\rfloor$(可以证明$n\le m$)

3.$\forall 1\le i\le n,\sum_{j=1}^{i}\lceil \frac{l_{j}}{2}\rceil\ge \sum_{j=1}^{i}\lceil \frac{x_{j}}{2}\rceil$

考虑必要性,第一个条件是因为$x_{i}$必然操作$x_{i}$次从而产生长为$x_{i}$的串,而$\sum_{i=1}^{n}l_{i}$即为序列长度(有剩余字符无解),因此相等

对于第2和3个限制(以2为例),每一个$x_{i}$产生了一个长度为$x_{i}$的'101010……'的序列,以此为$l_{i}$则恰好满足,那么选择最长的'101010……'前缀和一定不会变小,因此满足该条件

充分性的证明过程可以看原题解后半部分:

考虑dp,令$f[i][j][k][l]$表示有多少种$x_{1},x_{2},...,x_{i}$满足$\sum_{t=1}^{i}\lfloor \frac{x_{t}}{2}\rfloor=j$且$\sum_{t=1}^{i}\lceil \frac{x_{t}}{2}\rceil=k$且$x_{i}=l$,这样转移复杂度为$o(L^{5})$,最终答案即$\sum_{i=n}^{L}\sum_{l=1}^{L}f[i][\sum_{j=1}^{n}\lfloor\frac{l_{j}}{2}\rfloor][\sum_{k=1}^{n}\lceil\frac{l_{k}}{2}\rceil][l]$

由于$x_{1}\ge x_{2}\ge ...\ge x_{i}$,而$\sum_{j=1}^{i}x_{i}\le L$,因此$l\le \frac{L}{i}$,再通过前缀和可以优化到$o(L^{3}\ln L)$,空间上通过对第一维滚动可以做到$o(L^{3})$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 305
 4 #define mod 1000000007
 5 int n,m,ans,a[N],s1[N],s2[N],f[2][N][N][N];
 6 char s[N];
 7 int main(){
 8     scanf("%s",s);
 9     int l=m=strlen(s);
10     for(int i=0;i<l/2;i++)swap(s[i],s[l-i-1]);
11     while (l){
12         if (s[0]=='0'){
13             printf("0");
14             return 0;
15         }
16         int p=1,ll=l;
17         n++;
18         l=0;
19         for(int i=0;i<ll;i++)
20             if (s[i]-'0'!=p)s[l++]=s[i];
21             else{
22                 a[n]++;
23                 p^=1;
24             }
25     }
26     for(int i=1;i<=m;i++)s1[i]=s1[i-1]+a[i]/2;
27     for(int i=1;i<=m;i++)s2[i]=s2[i-1]+(a[i]+1)/2;
28     f[0][0][0][m]=1;
29     for(int i=0,p=1;i<m;i++,p^=1){
30         for(int j=0;j<=s1[i+1];j++)
31             for(int k=0;k<=s2[i+1];k++)
32                 for(int l=1;l<=m/max(i-1,1);l++)f[p][j][k][l]=0;
33         for(int j=0;j<=s1[i];j++)
34             for(int k=0;k<=s2[i];k++){
35                 for(int l=m/max(i,1)-1;l;l--)
36                     f[p^1][j][k][l]=(f[p^1][j][k][l]+f[p^1][j][k][l+1])%mod;
37                 for(int l=1;l<=m/(i+1);l++)
38                     if ((j+l/2<=s1[i+1])&&(k+(l+1)/2<=s2[i+1]))
39                         f[p][j+l/2][k+(l+1)/2][l]=(f[p][j+l/2][k+(l+1)/2][l]+f[p^1][j][k][l])%mod;
40             }
41         if (i>=n-1)
42             for(int j=1;j<=m;j++)ans=(ans+f[p][s1[n]][s2[n]][j])%mod;
43     }
44     printf("%d",ans);
45 }
View Code

 

posted @ 2020-10-23 16:00  PYWBKTDA  阅读(245)  评论(0编辑  收藏  举报