@一句话题解 - 2020.03@

咕咕咕。

这些题目倒不一定是我 3 月才做的,有可能是我之前做了现在才写的题解。

topcoder - SRM545D1L3:按位考虑,除非该位全是 1,否则两边必须各自至少有一个 0。容斥哪些位有一边全为 1,利用并查集算出结果。

#include <cstdio>
#include <vector>
using namespace std;

typedef long long ll;

class SetAndSet{
    public:
        int a[20][50], cnt[20], fa[20][50];
        int find(int t, int x) {return fa[t][x] = (fa[t][x] == x ? x : find(t, fa[t][x]));}
        bool unite(int t, int x, int y) {
            int fx = find(t, x), fy = find(t, y);
            if( fx != fy ) {
                fa[t][fx] = fy;
                return true;
            }
            else return false;
        }
        ll ans; int n;
        void dfs(int d, int k, int f) {
            if( d == 20 ) {
                ans += f*((1LL << k) - 2);
                return ;
            }
            if( d )
                for(int i=0;i<n;i++) fa[d][i] = fa[d-1][i];
            else for(int i=0;i<n;i++) fa[d][i] = i;
            dfs(d + 1, k, f);
            if( cnt[d] ) {
                for(int i=1;i<cnt[d];i++)
                    if( unite(d, a[d][0], a[d][i]) ) k--;
                dfs(d + 1, k, -f);
            }
        }
        ll countandset(vector<int>A) {
            n = A.size();
            for(int i=0;i<20;i++) {
                cnt[i] = 0;
                for(int j=0;j<n;j++)
                    if( !((A[j] >> i) & 1) ) a[i][cnt[i]++] = j;
            }
            dfs(0, n, 1);
            return ans;
        }
};

ZOJ - 4064:考虑容斥,枚举哪些格子禁止覆盖。只有相邻禁止覆盖的格子才有贡献,所以记 dp[i][j] 表示最近一个禁止覆盖位置为 i,有 j 个可以选择覆盖的区间的方案数*容斥系数,转移随便做。本题有点卡常。

#include <cstdio>

const int MAXN = 100;
const int MOD = int(1E9) + 7;

inline int add(int x, int y) {return (x + y >= MOD ? x + y - MOD : x + y);}
inline int sub(int x, int y) {return (x - y < 0 ? x - y + MOD : x - y);}
inline int mul(int x, int y) {return 1LL * x * y % MOD;}

int pow_mod(int b, int p) {
    int ret = 1;
    for(int i=p;i;i>>=1,b=mul(b,b))
        if( i & 1 ) ret = mul(ret, b);
    return ret;
}

int f[MAXN + 5][MAXN*MAXN + 5], A[MAXN + 5], n, m;

void solve() {
    scanf("%d%d", &n, &m);
    for(int i=1;i<=n;i++)
        scanf("%d", &A[i]);
    A[n + 1] = f[0][0] = 1;
    for(int i=0;i<=n;i++) {
        int t = i*(i + 1)/2;
        for(int j=0;j<=t;j++) {
            if( f[i][j] ) {
                for(int k=i+1;k<=n+1;k++) {
                    if( A[k] == 1 ) {
                        f[k][j+(k-i)*(k-i-1)/2] = add(f[k][j+(k-i)*(k-i-1)/2], f[i][j]);
                        break;
                    }
                    else if( A[k] == 2 )
                        f[k][j+(k-i)*(k-i-1)/2] = sub(f[k][j+(k-i)*(k-i-1)/2], f[i][j]);
                }
            }
        }
    }
    int ans = 0, t = n*(n + 1)/2;
    for(int i=0;i<=t;i++)
        ans = add(ans, mul(f[n+1][i], pow_mod(i, m)));
    for(int j=0;j<=n+1;j++)
        for(int k=0;k<=t;k++)
            f[j][k] = 0;
    printf("%d\n", ans);
}

int main() {
    int T; scanf("%d", &T);
    while( T-- ) solve();
}

猜你喜欢

转载自www.cnblogs.com/Tiw-Air-OAO/p/12409459.html