zoukankan      html  css  js  c++  java
  • [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 1le ile n,sum_{j=1}^{i}lfloor frac{l_{j}}{2} floorge sum_{j=1}^{i}lfloor frac{x_{j}}{2} floor$(可以证明$nle m$)

    3.$forall 1le ile n,sum_{j=1}^{i}lceil frac{l_{j}}{2} ceilge sum_{j=1}^{i}lceil frac{x_{j}}{2} ceil$

    考虑必要性,第一个条件是因为$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} floor=j$且$sum_{t=1}^{i}lceil frac{x_{t}}{2} ceil=k$且$x_{i}=l$,这样转移复杂度为$o(L^{5})$,最终答案即$sum_{i=n}^{L}sum_{l=1}^{L}f[i][sum_{j=1}^{n}lfloorfrac{l_{j}}{2} floor][sum_{k=1}^{n}lceilfrac{l_{k}}{2} ceil][l]$

    由于$x_{1}ge x_{2}ge ...ge x_{i}$,而$sum_{j=1}^{i}x_{i}le L$,因此$lle 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
  • 相关阅读:
    C#中任意类型数据转成JSON格式
    数据库用户映射到SQL Server登录名
    浅述WinForm多线程编程与Control.Invoke的应用
    Git错误一例
    提高VS2010/VS2012编译速度
    给有兴趣、有责任要讲课、分享的朋友推荐两本书
    中国剩余定理
    中国剩余定理
    洛谷1546 最短网路
    洛谷1111 修复公路
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/13864656.html
Copyright © 2011-2022 走看看