【11.8校内测试】【倒计时2天】【状压DP】【随机化?/暴力小模拟】

Solution

数据范围疯狂暗示状压,可是一开始发现状态特别难受。

将每一层的奇偶性状压,预处理所有状态的奇偶性。每一层的输入代表的其实可以是下一层某个点可以被从这一层哪些点转移到。

所以枚举每个状态,再枚举下一层转移到哪个点,统计这个点被这个状态更新的话正边和反边分别的奇偶性,转移即可。

第二层和最后一层单独处理即可。

Code

#include<bits/stdc++.h>
#define mod 998244353
using namespace std;

int x, dp[2][(1 << 11)], pre[(1 << 11)], up[1 << 11], dn[1 << 11];
int m, k;

int read () {
    int x = 0, f = 0; char c = getchar ();
    while (!isdigit (c)) f |= (c == '-'), c = getchar ();
    while (isdigit (c)) x = x * 10 + c - '0', c = getchar ();
    return f ? -x : x;
}

void init() {
    for(int i = 0; i < (1 << k); i ++)
        pre[i] = (i & 1) ^ pre[i >> 1];
}

int main() {
    freopen("adore.in", "r", stdin);
    freopen("adore.out", "w", stdout);
    scanf("%d%d", &m, &k);
    int sta = 0;
    for(int i = 0; i < k; i ++)    {
        x = read(),    sta |= (x << i);
    }
    dp[0][sta] = 1; init(); 
    int now = 0;
    for(int i = 1; i < m - 2; i ++) {
        now ^= 1;
        memset(dp[now], 0, sizeof(dp[now]));
        memset(up, 0, sizeof(up));
        memset(dn, 0, sizeof(dn));
        for(int u = 0; u < k; u ++)
            for(int v = 0; v < k; v ++) {
                x = read();
                up[u] |= (x << v);////反边 u能被那些点更新过来 
                dn[v] |= (x << u);////正边 
            }
        for(int s = 0; s < (1 << k); s ++)
            if(dp[now ^ 1][s]) {
                int A = 0, B = 0;
                for(int j = 0; j < k; j ++)
                    A |= ((pre[s & up[j]]) << j), B |= ((pre[s & dn[j]]) << j);
                dp[now][A] = (dp[now][A] + dp[now ^ 1][s]) % mod;
                dp[now][B] = (dp[now][B] + dp[now ^ 1][s]) % mod;
            }
    }
    int st = 0;
    for(int i = 0; i < k; i ++)    x = read(), st |= (x << i);
    int ans = 0;
    for(int s = 0; s < (1 << k); s ++)
        if(!pre[st & s])    ans = (ans + dp[now][s]) % mod;
    printf("%d", ans);
    return 0;
}

Solution

!!!原来是有$n+1$排!!是说为什么每次闪退QAQ

其实就是小模拟,直接三层for循环找到答案退出即可QAQ这个复杂度太有欺骗性了!!

其实随机搞更快???

Code

#include<bits/stdc++.h>
using namespace std;

int n, t1, t2, num[6005];
string s;
bitset < 12005 > b[6005];

int main() {
    freopen("confess.in", "r", stdin);
    freopen("confess.out", "w", stdout);
    srand(time(0));
    scanf("%d", &n);
    for(int i = 0; i <= n; i ++) {
        cin >> s;
        int len = s.length();
        for(int j = 0; j < len; j ++) {
            int a = s[j] - 33;
            for(int k = 5; k >= 0; k --)if(num[i]<(n<<1))    b[i][++num[i]] = ((a >> k) & 1);
        }
    }
    int cnt;
    while(1) {
        int i = rand() % (n + 1);
        int j = rand() % (n + 1);
        if(i == j) j ++;
        if((b[i] & b[j]).count() >= (n / 2)) {
            if(i > j)    swap(i, j);
            printf("%d %d", i+1, j+1); return 0;
        }
    }
    printf("NO Solution");
    return 0;
}

 

posted @ 2018-11-08 16:16  Wans_ovo  阅读(163)  评论(0编辑  收藏  举报