CF1542D

直接计算子集 (B)(f(B)) 不太现实,所以考虑计算每一个数的贡献

我们规定相同的数序号更小的数的更小

对于数 (a_i) ,显然对它有影响的只有所有的 "-", 它前面小于等于它的数,它后面小于它的数

所以枚举每一个数的位置 (i) ,考虑 (dp_j) 表示小于等于 (a_i) 的数的个数为 (j) 得方案数

转移方程如下

for(int i=1; i<=n; i++) {
        if(a[i] != -1) {
            int mx = 0;
            memset(dp, 0, sizeof dp);
            dp[0] = 1;
            for(int j=1; j<=n; j++) {
                if(j < i) {
                    if(a[j] == -1) {
                        dp[0] = (2*dp[0]) % mod;
                        for(int k=0; k<mx; k++)
                            dp[k] = (dp[k] + dp[k+1]) % mod;
                    }
                    else {
                        bool s = (a[j] <= a[i]);
                        mx += s;
                        for(int k=mx; k>=s; k--)
                            dp[k] = (dp[k] + dp[k-s]) % mod;
                    }
                }
                else if(j == i) {
                    mx += 1;
                    for(int k=mx; k; k--)
                        dp[k] = dp[k-1];
                    dp[0] = 0;  
                }
                else {
                    if(a[j] == -1) {
                        for(int k=1; k<mx; k++)
                            dp[k] = (dp[k] + dp[k+1]) % mod;
                    }
                    else {
                        bool s = (a[j] < a[i]);
                        mx += s;
                        for(int k=mx; k; k--)
                            dp[k] = (dp[k] + dp[k-s]) % mod;
                    }
                }
            }
原文地址:https://www.cnblogs.com/ullio/p/14983916.html