Atcoder agc020E

这题看上去就有一股乱搞的感觉。
注意到答案显然可以DP,对于一个字符串S SS,我们令F [ S ] F[S]F[S]代表S SS的所有子集的编码方案数之和。那么考虑最左边被编码的是哪个子串,有F [ S ] = ( 1 + [ S 1 = 1 ] ) ⋅ F [ S 2... ∣ s ∣ ] + ∑ i j ≤ n F [ S 1... i   a n d   S i + 1...2 i   a n d   . . . S ( j − 1 ) i + 1... i j ] ⋅ F [ S i j + 1... ∣ s ∣ ] F[S]=(1+[S_1=1]) \cdot F[S_{2...|s|}]+\sum_{ij\leq n}F[S_{1...i} \ and \ S_{i+1...2i} \ and \ ... S_{(j-1)i+1...ij}] \cdot F[S_{ij+1...|s|}]F[S]=(1+[S1=1])F[S2...s]+ijnF[S1...i and Si+1...2i and ...S(j1)i+1...ij]F[Sij+1...s]
直接对这个DP记忆化就能通过了。题解有高超技巧证明状态数目上界是O ( n 3 + 2 n 8 ) \mathcal O(n^3+2^{\frac{n}{8}})O(n3+28n)的,我用了map<string,int>导致巨慢。

#include <bits/stdc++.h>
#define MOD 998244353

using namespace std;

typedef long long ll;

map <string,int> mp;

void merge(string &x,string y) {
  for(int i=0;i<x.length();i++)
    if (y[i]=='0') x[i]='0';
}

int dp(string s) {
  if (s.empty()) return 1;
  if (mp.count(s)) return mp[s];
  int n=s.length(),ans=0;
  ans=(ans+((s[0]=='1')?2LL:1LL)*dp(s.substr(1,n)))%MOD;
  for(int i=1;2*i<=n;i++) {
  	string cur=s.substr(0,i);
  	for(int j=2;i*j<=n;j++) {
  		merge(cur,s.substr(i*(j-1),i*j));
  		ans=(ans+(ll)dp(cur)*dp(s.substr(i*j,n)))%MOD;
	  }
  }
  return mp[s]=ans;
}

int main() {
  string s;
  cin>>s;
  cout<<dp(s)<<endl;
  return 0;
}


版权声明:本文为qq_38609262原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。