CF1738EBalance Addicts

CF1738EBalance Addicts

原题: CF1738EBalance Addicts

题目大意

\(n\)个数的数列,把它分成若干个子集,保证所有子集的和能够组成一个回文数列,求\(mod\ 998244353\)后的方案数。

做法

思路

先分别从头和尾找到一段序列的和相同,记为\(l1\ r2\)然后从\(l1\ r2\)开始寻找一段最长的和相等的序列记为\(r1\ l2\)
此时答案为

\[ans *= \sum_{i = 0}^{min(r1 - l1 + 1 , r2 - l2 + 1)}C_{r1 - l1 + 1}^i * C_{r2 - l2 + 1}^i \]

注意

1、如果此时\(l1\ r2\)之间的数都为\(0\)
显然:\(l1\ r2\)之间的数都可以随便选,那么将\(ans *= 2^{r2 - l1 + 1}\)即可退出
2、预处理\(sum1\ sum2\ tpow\)表示前缀和、后缀和、2的\(n\)次方
3、记得\(mod\ 998244353\)

code

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5; 
const long long mod = 998244353;
int n;
long long ans , ans1 , sum1[N + 5] , sum2[N + 5] , fac[N + 5] , inv[N + 5] , tpow[N + 5] , a[N + 5];  
long long pw(long long x , long long y) {
    if(!y)
        return 1;
    long long z = pw (x , y / 2);
    z = z * z % mod;
    if(y & 1) 
        z = z * x % mod;
    return z; 
}
void pre() {
    fac[1] = fac[0] = 1;
    for(int i = 2 ; i <= N ; i++) {
        fac[i] = fac[i - 1] * i % mod ;
    }
    inv[N] = pw (fac[N] , mod - 2);
    for(int i = N - 1 ; i >= 0 ; i--) {
        inv[i] = inv[i + 1] * (i + 1) % mod;
    }
    tpow[0] = 1;
    for (int i = 1 ; i <= N ; i++)
        tpow[i] = tpow[i - 1] * 2 % mod;
}
long long C(int x , int y) {
    if(x<0||y<0) return 0;
    if(x < y) 
        return 0;
    return fac[x] * inv[y] % mod * inv[x - y] % mod; 
}
int main () {
    pre ();
    int T;
    scanf ("%d" , &T);
    while (T--) {
        ans = 1;
        scanf ("%d" , &n);
        for (int i = 1 ; i <= n ; i++) {
            scanf ("%d" , &a[i]);
        }
        for (int i = 1 ; i <= n ; i++) {
            sum1[i] = sum1[i - 1] + a[i];
        }
        for (int i = n - 1; i >= 1 ; i--) {
            sum2[i] = sum2[i + 1] + a[i + 1];
        }
        for (int l1 = 1 , r2 = n - 1 , l2 , r1; l1 <= r2 ; l1 = r1 + 1 , r2 = l2 - 1) {
            while (l1 <= r2 && sum1[l1] != sum2[r2]) {
                if(sum1[l1] < sum2[r2]) 
                    l1 ++;
                else 
                    r2 --;
            }
            if (l1 > r2)
                break;
            if (sum1[l1] == sum1[r2]) {
                ans = tpow[r2 - l1 + 1] * ans % mod;
                break;
            }
            r1 = l1 , l2 = r2; 
            while (sum1[r1 + 1] == sum1[l1]) 
                r1 ++;
            while (sum2[l2 - 1] == sum2[r2])
                l2 --;
            ans1 = 0;
            for (int i = 0 ; i <= min(r1 - l1 + 1 , r2 - l2 + 1) ; i++) {
                ans1 = (ans1 + (C (r1 - l1 + 1 , i) * C (r2 - l2 + 1 , i) %mod) ) %mod;
            }
            ans = ans * ans1 % mod;
        }
        printf("%lld\n" , ans);
        for (int i = 1 ; i <= n ; i++) 
            sum1[i] = sum2[i] = 0;
    }
    return 0;
}
posted @ 2023-03-23 20:05  2020fengziyang  阅读(26)  评论(0编辑  收藏  举报