zoukankan      html  css  js  c++  java
  • 「LibreOJ NOI Round #2」不等关系

    「LibreOJ NOI Round #2」不等关系

    暑假 dls 讲过但是当时掉线了。。

    考虑我们如果直接无视 > 符号,现在这个排列就一定是一些下降的子段组合在一起的。我们假设这些段的长度分别是 $ a_1,a_2,dots ,a_k $ 那么算出来方案数量是

    [frac{n!}{a_1!a_2!dots a_k!} ]

    因为我们可以任意定一个排列,为了满足条件只需要把这些子段排个序。理解一下发现就是这个东西。

    但是我们还有 > 符号啊,既然不好处理,我们可以考虑容斥,比如, <<><> 这个序列,它的答案就可以推出来

    <<><> = <<*<* - <<<<* - <<*<< + <<<<<
    

    为啥是对的?我们可以把每个位置拖出来,发现 这个位置是 > = 这个位置关系任意 - 这个位置是 >

    所以我们可以考虑用 dp 做这个容斥, $ dp[i] $ 表示前 $ i $ 个关系被满足的方案数量,则有

    [dp[i] = i![s_i='>']sum_j [s_j='>'](-1)^{cnt_i-cnt_j-1}frac{1}{(i-j)!} imes dp[j] ]

    这个东西是可以方便的分治FFT的,化开就是:

    [dp[i] = i!(-1)^{c_i}sum_{j+k=i} [s_j='>']-1^{c_j+1}dp[j] imes frac{1}{k!} ]

    写的时候不知道哪里系数犯了,算出来是负的。。。

    #include "iostream"
    #include "algorithm"
    #include "cstring"
    #include "cstdio"
    using namespace std;
    #define MAXN 400006
    int n , m;
    #define P 998244353
    typedef long long ll;
    
    namespace cdqntt {
        int Pow(int x, int y) {
            int res = 1;
            while (y) {
                if (y & 1) res = res * (ll) x % P;
                x = x * (ll) x % P, y >>= 1;
            }
            return res;
        }
    
        int wn[2][MAXN];
    
        void getwn(int l) {
            for (int i = 1; i < (1 << l); i <<= 1) {
                int w0 = Pow(3, (P - 1) / (i << 1)), w1 = Pow(3, P - 1 - (P - 1) / (i << 1));
                wn[0][i] = wn[1][i] = 1;
                for (int j = 1; j < i; ++j)
                    wn[0][i + j] = wn[0][i + j - 1] * (ll) w0 % P,
                            wn[1][i + j] = wn[1][i + j - 1] * (ll) w1 % P;
            }
        }
    
        int rev[MAXN];
    
        void getr(int l) { for (int i = 1; i < (1 << l); ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << l - 1); }
    
        void NTT(int *A, int len, int f) {
            for (int i = 0; i < len; ++i) if (rev[i] < i) swap(A[i], A[rev[i]]);
            for (int l = 1; l < len; l <<= 1)
                for (int i = 0; i < len; i += (l << 1))
                    for (int k = 0; k < l; ++k) {
                        int t1 = A[i + k], t2 = A[i + l + k] * (ll) wn[f][l + k] % P;
                        A[i + k] = (t1 + t2) % P;
                        A[i + l + k] = (t1 - t2 + P) % P;
                    }
            if (f == 1) for (int inv = Pow(len, P - 2), i = 0; i < len; ++i) A[i] = A[i] * (ll) inv % P;
        }
    
        int f[MAXN];
        int A[MAXN], B[MAXN] , J[MAXN] , ok[MAXN] , t[MAXN];
    
        void CDQ(int *a, int l, int r) {
    //        cout << l << ' ' << r << endl;
            if (l == r) return;
            int m = l + r >> 1;
            CDQ(a, l, m);
            int p = 1, len = 0;
            while (p <= (r - l + 1) * 2) p <<= 1, ++len;
            getr(len);
            for (int i = 0; i < p; ++i) A[i] = B[i] = 0;
            for (int i = l; i <= m; ++i) if( ok[i] ) B[i - l] = ( 1ll * ( ( t[i] & 1 ) ? P-1 : 1 ) * f[i] ) % P;//, cout << B[i - l] <<' ';
            for (int i = 0; i <= r - l; ++i) A[i] = J[i];// , cout << A[i] << ' ';
            puts("");
            NTT(A, p, 0), NTT(B, p, 0);
            for (int i = 0; i < p; ++i) A[i] = 1ll * A[i] * B[i] % P;
            NTT(A, p, 1);
            for (int i = m + 1; i <= r; ++i) f[i] = (f[i] + 1ll * ( ( t[i] & 1 ) ? 1 : P-1 ) * A[i - l]) % P;
            CDQ(a, m + 1, r);
        }
    }
    
    int A[MAXN];
    char s[MAXN];
    
    int main() {
    //    freopen("in.in","r",stdin);
        using namespace cdqntt;
        J[0] = 1;for( int i = 1 ; i < MAXN ; ++ i ) J[i] = 1ll * J[i - 1] * Pow( i , P - 2 ) % P;
        scanf("%s",s + 1);
        n = strlen( s + 1 ) + 1;
        int pre = 0;
        for( int i = 1 ; i <= n ; ++ i ) {
            if( s[i] == '>' ) ok[i] = 1;
            t[i] = t[i - 1] + ok[i];
        }
        int l = 0 , len = 1;
        while( len <= n + n ) len <<= 1 , ++ l;
        getwn( l );
        f[0] = 1 , ok[0] = 1;
        CDQ( f , 0 , n );
        cout << ( P - 1ll * f[n] * Pow( J[n] , P - 2 ) % P ) << endl;
    }
    
  • 相关阅读:
    48. Rotate Image
    83. Remove Duplicates from Sorted List
    46. Permutations
    HTML5笔记
    18. 4Sum
    24. Swap Nodes in Pairs
    42. Trapping Rain Water
    Python modf() 函数
    Python min() 函数
    Python max() 函数
  • 原文地址:https://www.cnblogs.com/yijan/p/12326328.html
Copyright © 2011-2022 走看看