2 条题解

  • 0
    @ 2026-5-7 19:52:46

    爆标做法。考虑把 DP 套 DP 直接扔掉,钦定当前状态按后 1/2/41/2/4 个分段,强行分讨去掉重复情况:

    最后一个分段,fifi+fi1f_i\gets f_i+f_{i-1}

    [i1,i][i-1,i] 相邻,最后两个分段,要求这两个交换,否则被两个 11 段替代,fifi+fi2f_i\gets f_i+f_{i-2}

    [i3,i][i-3,i] 是正方形,最后四个分段,先让 fifi+24fi4f_i\gets f_i+24f_{i-4},然后扣掉可以被替代的方案。

    ii 分一段的某个方案替代:

    [i3,i][i-3,i] 顺序是 12341234,被四个 11 段替代,fififi4f_i\gets f_i-f_{i-4}

    [i3,i][i-3,i] 顺序是 2314,3124,32142314,3124,3214,这三种情况只可能被 [i4,i1][i-4,i-1] 分段的情况替代,若 [i4,i1][i-4,i-1] 是正方形则 fifi3fi5f_i\gets f_i-3f_{i-5}

    [i3,i][i-3,i] 顺序是 13241324,若 [i2,i1][i-2,i-1] 相邻,此时可以钦定为按 i3,[i2,i1]i-3,[i-2,i-1] 分段。若 [i4,i1][i-4,i-1] 分段,能被 [i4,i3],[i2,i1][i-4,i-3],[i-2,i-1] 替代。若按 [i5,i4][i-5,i-4] 分段,能被 i5,i4i-5,i-4 替代;若按 [i7,i4][i-7,i-4] 分段,在 [i7,i5][i-7,i-5] 中必有两个相邻,可以 2+12+1 分段。因此可以转移 fififi4f_i\gets f_i-f_{i-4},否则若 [i5,i1][i-5,i-1] 是正方形就转移 fififi5f_i\gets f_i-f_{i-5}

    [i3,i][i-3,i] 顺序是 21342134,若 i3,i2i-3,i-2 相邻,钦定 [i3,i2],i1,i[i-3,i-2],i-1,i 分段,[i5,i2][i-5,i-2] 分段的情况一定有 [i5,i4][i-5,i-4] 相邻,总是可以分成两段 22,因此已经被包含,转移 fififi4f_i\gets f_i-f_{i-4}。否则情况比较复杂:

    如果能分段 [i4,i1][i-4,i-1],就是 fi4f_{i-4}。另一种方案是分段 i1,ii-1,i[i5,i2][i-5,i-2] 的顺序是 21432143i5,i4i-5,i-4 必须交换,否则被 [i4,i1][i-4,i-1] 分段的情况覆盖)。我们已知 [i3,i2][i-3,i-2] 在交错的位置,因此 [i5,i2][i-5,i-2] 必须能成段。注意,此时我们的前提条件是扣除 [i3,i][i-3,i] 成段的方案数。

    现在我们考虑 [i3,i][i-3,i] 成段时 [i7,i4][i-7,i-4] 要成段,考虑 i7,i6i-7,i-6 是否交换。若不交换,那这两个成段的限制已经满足,为 fi8f_{i-8}。否则限制变为 [i5,i2],[i7,i4][i-5,i-2],[i-7,i-4] 要能成段且 i7,i6i-7,i-6 必须交换。发现这变成了一个子问题,我们可以拿一个 gig_i 算出,为 $g_i=\begin{cases}g_{i-2}+f_{i-4}&\ [i-3,i]\text{ is valid}\\0&\ \text{otherwise}\end{cases}$。转移就是 fifigi4f_i\gets f_i-g_{i-4}

    [i4,i1][i-4,i-1] 不能分段,就只有分段 i1,i,[i5,i2]i-1,i,[i-5,i-2],比上面多一种 i5,i4i-5,i-4 不交换的情况 fi6f_{i-6}。转移是 fififi6gi4f_i\gets f_i-f_{i-6}-g_{i-4}

    若被 [i1,i][i-1,i] 分一段的某个方案替代(首先要求 i1,ii-1,i 相邻):

    ii 不能留在原位,否则被上一种情况统计,因此只有 2143,12432143,1243 型。

    12431243 型,可以钦定为按 [i4,i3],[i2,i1][i-4,i-3],[i-2,i-1] 分段。这要求 i4i-4 是断点,和上面的讨论类似,若按 [i6,i3][i-6,i-3] 分段能拆成 2+22+2,若按 [i7,i4][i-7,i-4] 分段能将 [i7,i5][i-7,i-5] 拆成 i+2i+2。转移 fififi4f_i\gets f_i-f_{i-4}

    21432143 型,因为 [i3,i2][i-3,i-2] 也相邻,就能被 [i3,i2],[i1,i][i-3,i-2],[i-1,i] 替代(同上,[i5,i2][i-5,i-2] 分段的情况被包含)。转移 fififi4f_i\gets f_i-f_{i-4}

    综上,我们做到了小常数 O(n)O(n)

    #include<bits/stdc++.h>
    using namespace std;
    const int mod=1000000007;
    int t,n,f[100005],g[100005];
    char s[100005];
    bool check2(int x){
      return x>=2&&(abs(s[x]-s[x-1])==3||(abs(s[x]-s[x-1])==1&&(s[x]+s[x-1])%3!=1));
    }
    bool check4(int x){
      if(x<4)return 0;
      int t=0;
      for(int i=0;i<4;i++)t|=1<<(s[x-i]-'0');
      return t==54||t==108||t==432||t==864;
    }
    int main(){
      ios::sync_with_stdio(0),cin.tie(0),f[0]=1,cin>>t;
      while(t--){
        cin>>s+1,n=strlen(s+1);
        for(int i=1;i<=n;i++){
          g[i]=check4(i)?(g[i-2]+f[i-4])%mod:0,f[i]=f[i-1];
          if(check2(i))f[i]=(f[i]+f[i-2])%mod;
          if(check4(i)){
            f[i]=(f[i]+23ll*f[i-4])%mod;
            if(check4(i-1))f[i]=((f[i]-3ll*f[i-5])%mod+mod)%mod;
            if(check2(i-1))f[i]=(f[i]-f[i-4]+mod)%mod;
            else if(check4(i-1))f[i]=(f[i]-f[i-5]+mod)%mod;
            if(check2(i-2))f[i]=(f[i]-f[i-4]+mod)%mod;
            else{
              if(check4(i-1)){
                f[i]=(f[i]-f[i-5]+mod)%mod;
                if(check4(i-2))f[i]=(f[i]-g[i-4]+mod)%mod;
              }
              else f[i]=(f[i]-g[i-2]+mod)%mod;
            }
            if(check2(i))f[i]=(f[i]-2ll*f[i-4]%mod+2*mod)%mod;
          }
        }
        cout<<f[n]<<'\n';
      }
      return 0;
    }
    
    • 0
      @ 2025-10-8 17:14:24
      #include<bits/stdc++.h>
      #define rep(i,a,b) for(int i=(a);i<=(b);++i)
      using namespace std;
      const int N=1e5+9,Mod=1e9+7;
      int T,n,a[N];
      char s[N];
      bool chk2(array<int,2>a){
          sort(a.begin(),a.end());
          if(a[0]+3==a[1])return 1;
          if(a[0]+1==a[1]&&a[0]!=3&&a[0]!=6)return 1;
          return 0;
      }
      bool chk4(array<int,4>a){
          sort(a.begin(),a.end());
          if(a[0]==1&&a[1]==2&&a[2]==4&&a[3]==5)return 1;
          if(a[0]==2&&a[1]==3&&a[2]==5&&a[3]==6)return 1;
          if(a[0]==4&&a[1]==5&&a[2]==7&&a[3]==8)return 1;
          if(a[0]==5&&a[1]==6&&a[2]==8&&a[3]==9)return 1;
          return 0;
      }
      bool equ(vector<int>a,vector<int>b){sort(a.begin(),a.end()),sort(b.begin(),b.end());return a==b;}
      void Upd(int&x,int y){
          x+=y;
          if(x>=Mod)x-=Mod;
      }
      int f[2][16005],cur;
      vector<int>S;
      bool vis[16005],ck2[N],ck4[N];
      bool good1[10][10][10],good2[10][10];
      int H(int x,int y,int z,int a,int b,int c,int d){return x*1600+y*160+z*16+a*8+b*4+c*2+d;}
      void solve(){
          cin>>s+1,n=strlen(s+1);
          rep(i,1,n)a[i]=s[i]-'0';
          memset(f,0,sizeof(f)),memset(vis,0,sizeof(vis)),cur=0;
          f[0][1]=1,S.push_back(1);
          rep(i,0,n+1)ck2[i]=ck4[i]=0;
          rep(i,2,n)ck2[i]=chk2({a[i-1],a[i]});
          rep(i,4,n)ck4[i]=chk4({a[i-3],a[i-2],a[i-1],a[i]});
          rep(i,1,n){
              memset(f[cur^1],0,sizeof(f[cur^1]));
              vector<int>nS;
              for(int s:S)vis[s]=0;
              vector<int>trs;
              rep(j,max(1,i-3),min(n,i+3))trs.push_back(a[j]);
              sort(trs.begin(),trs.end());
              trs.resize(unique(trs.begin(),trs.end())-trs.begin());
              for(int s:S){
                  int a3=(s>>4)/100,a2=(s>>4)/10%10,a1=(s>>4)%10,f3=(s>>3)&1,f2=(s>>2)&1,f1=(s>>1)&1,f0=s&1;
                  int val=f[cur][s];
                  for(int a0:trs){
                      int nf=0;
                      if(a[i]==a0)nf|=f0;
                      if(!nf){
                          if(i>1&&ck2[i]&&equ({a[i-1],a[i]},{a1,a0}))nf|=f1;
                          if(!nf&&i>3&&ck4[i]&&equ({a[i-3],a[i-2],a[i-1],a[i]},{a3,a2,a1,a0}))nf|=f3;
                      }
                      if(f2+f1+f0+nf==0)continue;
                      int na2=a2,na1=a1,na0=a0,nf2=f2,nf1=f1;
                      if(!f2)na2=0;
                      if(!f2&&!f1)na1=0;
                      if(!f2&&!f1&&!f0)na0=0;
                      if(!good1[na2][na1][na0])na2=0,nf2=0;
                      if(!good2[na1][na0])na1=0,nf1=0;
                      int nH=H(na2,na1,na0,nf2,nf1,f0,nf);
                      if(!vis[nH])vis[nH]=1,nS.push_back(nH);
                      Upd(f[cur^1][nH],val);
                  }
                  f[cur][s]=0;
              }
              S=nS,cur^=1;
          }
          int ans=0;
          for(int s:S)if(s&1)Upd(ans,f[cur][s]);
          cout<<ans<<'\n';
      }
      int main(){
          cin>>T;
          rep(i,0,9)rep(j,0,9)rep(k,0,9)rep(l,0,9)if(chk4({i,j,k,l}))good1[i][j][k]=good2[i][j]=1;
          while(T--)solve();
          return 0;
      }
      
      • 1

      信息

      ID
      7644
      时间
      4000ms
      内存
      512MiB
      难度
      9
      标签
      递交数
      44
      已通过
      4
      上传者