牛客练习赛98D Son String (组合数学 计数DP)

https://ac.nowcoder.com/acm/contest/11188/D
image

  • 划分问题有时候适用隔板法
  • 要求对称的1相等,我们做dp来划分状态
  • 全0的时候直接算每个位置放不放隔板,放边上等价全不放, 偶数个奇数时候,还要计算中间的0的全零的方案 101
#include<bits/stdc++.h>
//#include <bits/extc++.h>
using namespace std;
// using namespace __gnu_cxx;
// using namespace __gnu_pbds;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);  
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
#define li __int128_t
//#define int long long
const int N = 5e2 + 5;
const int M = 1e6 + 5;
const int mod = 998244353;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const double PI = acos(-1.0);
int a[N], n;
ll f[N];
ll qmi( ll m, ll k ) {
   ll res = 1 % mod;
   while( k ) {
   	if(k & 1) res = res * m % mod;
   	m = m * m % mod;
   	k >>= 1;
   }
   return res;
}
ll F[N];ll inv[N];
void init(int n){
   F[0]= inv[0] = 1;
   for(int i=1;i<=n;i++)F[i]=F[i-1]*i%mod;
   inv[n] = qmi(F[n], mod - 2);
   for(int i=n-1;i>=1;i--)inv[i]=inv[i+1]*(i+1)%mod;
}
ll C ( ll a, ll b ) {
   return F[a] * inv[b] % mod * inv[a - b] % mod;
}
int main() {
   init(505);
   string ss; cin >> ss;
   for ( int i = 0; i < ss.length(); ++ i ) {
   	if( (ss[i] - '0') & 1 ) a[ ++ n ] = i + 1;
   }
   int len = ss.length();
   if(!n) {
   	cout << qmi( 2, len - 1 ) << '\n'; return 0;
   }
   for ( int i = 1; i <= (n + 1) / 2 ; ++ i ) {
   	if( i == 1 ) {
   		int f1 = a[i] - 1, f2 = len - a[n];
   		for ( int j = 0; j <= min(f1, f2); ++ j) {
   			f[1] = (f[1] + C(f1, j) * C(f2, j) % mod) % mod; 
   		}
   	} else {
   		int f1 = a[i] - a[i - 1] - 1 + 1, f2 = a[n - i + 2] - a[n - i + 1] - 1 + 1;

   		for ( int j = 0; j <= min(f1, f2); ++ j) {
   			f[i] = (f[i] + C(f1, j) * C(f2, j) % mod * f[i - 1] % mod) % mod; 
   		}
   	}
   }

   if( n % 2 == 0 ) {
   	int num = a[n/2 + 1] - a[n / 2] - 1;
   	cout << f[ n / 2 ] * qmi( 2, num + 1) % mod << '\n';
   } else {
   	cout << f[ n / 2 + 1] % mod << '\n';
   }
   return 0;
}
posted @ 2022-05-03 17:45  qingyanng  阅读(23)  评论(0编辑  收藏  举报