[容斥原理][复杂度分析] SRM 555 Div1 Hard MapGuessing

Solution S o l u t i o n

可以枚举磁头的初始位置,计算出哪些地方是可以随便赋 0/1 0 / 1 的。
但这样一个初始序列可能会被多个磁头满足。就要用容斥去重。

ans=TS(1)|T|+12|P|P=RTR a n s = ∑ T ⊆ S ( − 1 ) | T | + 1 2 | P | P = ⋂ R ⊆ T R
直接dfs,若 P= P = ∅ 就退出搜索,这样复杂度是 O(n2n) O ( n 2 n ) 的。

// BEGIN CUT HERE

// END CUT HERE
#line 5 "MapGuessing.cpp"
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int N = 40;

string g, o;
int n, len;
ll a[N];
vector<ll> S;

class MapGuessing {

public:
    inline void CalcA(int p) {
    ll res = 0, S = 0;
    string tmp = g;
    int cnt = n, pos = p;
    for (char c: o) {
      if (isdigit(c)) {
        cnt -= (tmp[p] == g[p]);
        tmp[p] = c;
        cnt += (tmp[p] == g[p]);
        S |= 1ll << p;
        if (cnt == n) res = S;
      } else {
        if (c == '<') --p; else ++p;
        if (p < 0 || p >= n) return (void)(a[pos] = -1);
      }
    }
    a[pos] = res;
    }
    inline int sgn(int d) {
        return d & 1 ? 1 : -1;
    }
    inline int BitCount(ll S) {
        int cnt = 0;
        for (; S; S -= S & -S) ++cnt;
        return cnt;
    }
    inline ll dfs(int i, int d, ll P) {
        if (!P) {
            if (i == S.size()) return sgn(d);
            return 0;
        }
        if (i == S.size())
            if (d) return sgn(d) * (1ll << BitCount(P));
            else return 0;
        return dfs(i + 1, d, P)
            + dfs(i + 1, d + 1, P & S[i]);
    }
    ll countPatterns(string goal, vector <string> code) {
        g = goal; o.clear();
        for (string t: code) o += t;
        n = g.size(); len = o.size();
        for (int i = 0; i < n; i++) {
            CalcA(i);
            if (~a[i]) S.push_back(a[i]);
        }
        return dfs(0, 0, (1ll << n) - 1);
    }

// BEGIN CUT HERE
    public:
    void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); if ((Case == -1) || (Case == 4)) test_case_4(); if ((Case == -1) || (Case == 5)) test_case_5(); if ((Case == -1) || (Case == 6)) test_case_6(); }
    private:
    template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); }
    void verify_case(int Case, const long long &Expected, const long long &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } }
    void test_case_0() { string Arg0 = "000"; string Arr1[] = {"0"}; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); long long Arg2 = 4LL; verify_case(0, Arg2, countPatterns(Arg0, Arg1)); }
    void test_case_1() { string Arg0 = "001"; string Arr1[] = {"0>1"}; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); long long Arg2 = 5LL; verify_case(1, Arg2, countPatterns(Arg0, Arg1)); }
    void test_case_2() { string Arg0 = "000"; string Arr1[] = {"1>1>1"}; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); long long Arg2 = 1LL; verify_case(2, Arg2, countPatterns(Arg0, Arg1)); }
    void test_case_3() { string Arg0 = "11001"; string Arr1[] = {">><<<<><<"}; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); long long Arg2 = 0LL; verify_case(3, Arg2, countPatterns(Arg0, Arg1)); }
    void test_case_4() { string Arg0 = "1000101011"; string Arr1[] = {"1<<0>>0>1"}; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); long long Arg2 = 22LL; verify_case(4, Arg2, countPatterns(Arg0, Arg1)); }
    void test_case_5() { string Arg0 = "00000010000000000000000000000000"; string Arr1[] = {"><>>0<0<>>1>0><>", "<<0>>0<>><0>0>>><><", ">>>0<>", ">0><>>>>0<<><>>0>>>0<0>>0>"}; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); long long Arg2 = 13601LL; verify_case(5, Arg2, countPatterns(Arg0, Arg1)); }
    void test_case_6() { string Arg0 = "11100011010111111010100100110001101"; string Arr1[] = {"11111111111111111111"
,"1<><><><><><><><><>1"
,"1<>000>000><0<><0<>1"
,"1<0<><>0><0<00>00<>1"
,"1<>00<>000><0<0<0<>1"
,"1<><>0>0><0<0<><0<>1"
,"1<000<>0><0<0<><0<>1"
,"1<><><><><><><><><>1"
,"1<>000><000<>000><>1"
,"1<>0><><0<><>0><><>1"
,"1<>000><000<>000><>1"
,"1<><>0><><0<><>0><>1"
,"1<>000><000<>000><>1"
,"1<><><><><><><><><>1"
,"11111111111111111111"}; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); long long Arg2 = 90LL; verify_case(6, Arg2, countPatterns(Arg0, Arg1)); }

// END CUT HERE


};

// BEGIN CUT HERE
int main(void) {
    MapGuessing ___test;
    ___test.run_test(6);
    system("pause");
}
// END CUT HERE
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值