【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;
}

原文地址:https://www.cnblogs.com/wans-caesar-02111007/p/9929774.html

时间: 2024-10-11 05:29:55

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

CCF 201312-4 有趣的数 (数位DP, 状压DP, 组合数学+暴力枚举, 推公式, 矩阵快速幂)

问题描述 我们把一个数称为有趣的,当且仅当: 1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次. 2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前. 3. 最高位数字不为0. 因此,符合我们定义的最小的有趣的数是2013.除此以外,4位的有趣的数还有两个:2031和2301. 请计算恰好有n位的有趣的数的个数.由于答案可能非常大,只需要输出答案除以1000000007的余数. 输入格式 输入只有一行,包括恰好一个正整数n (4 ≤ n ≤ 1000). 输

NOJ 1116 哈罗哈的大披萨 【淡蓝】 [状压dp+各种优化]

我只能说,珍爱生命,远离卡常数的题...感谢陈老师和蔡神,没有他们,,,我调一个星期都弄不出来,,,, 哈罗哈的大披萨 [淡蓝] 时间限制(普通/Java) : 1000 MS/ 3000 MS          运行内存限制 : 65536 KByte总提交 : 73            测试通过 : 9 描述 热风哈罗哈(三牌楼)店正在搞活动:他们将提供一个大披萨给第一个告诉他们以下信息的人:一次购买任一种披萨,哪种单位面积的价格最低.问题初步想一想,好像是这么解决:“对于每个披萨计算平均

[POJ1038]状压DP

题意:给一个n*m的区域,里面有一些障碍物,往里面放2*3和3*2的矩形,矩形之间不能重叠,不能覆盖到障碍物,求能放置的最大个数.(n<=150,m<=10) 思路:看到m=10就应该往状压dp方面想了.由于有3*2的矩形,所以需要记录2行的状态,粗略估计状态数高达150*2^20=1.5*1e8,这么多状态必然超时,注意到如果(i-1,j)为0了,无论(i,j)为1或0,(i,j)都不能放矩形,于是知道有很多无用的或者说不合法的状态,两行的状态用m位3进制数表示同样能实现转移.由于3进制数操

2015广东工业大学ACM校赛 I 游戏王 (状压dp)

Problem I: 游戏王 Description 小学的时候,Stubird非常喜欢玩游戏王,有一天,他发现了一个绝佳的连锁组合,这个连锁组合需要6张卡, 可是他一张都没有,但是他的那些朋友们有,不过当然,他们不会白给,不过也不排除有人和他交情好,送给他了. 不过他们有成全别人的美德,当他们看到Stubird已经有某些他们喜欢的卡的时候,他们会给他优惠,或者更贵也说不定 嘛不过,你可以把有的卡片藏起来,不告诉他们,来获得更低的价格. 问他最少需要多少钱才可以集齐所有的卡. Input 第一行

poj 2411 Mondriaan&#39;s Dream(状压DP)

Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12232   Accepted: 7142 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series

(状压dp)uva 10817 Headmaster&#39;s Headache

题目地址 1 #include <bits/stdc++.h> 2 typedef long long ll; 3 using namespace std; 4 const int MAX=1e5+5; 5 const int INF=1e9; 6 int s,m,n; 7 int cost[125]; 8 //char sta[MAX]; 9 string sta; 10 int able[125]; 11 int dp[125][1<<8][1<<8]; 12 in

HDU 4336 容斥原理 || 状压DP

状压DP :F(S)=Sum*F(S)+p(x1)*F(S^(1<<x1))+p(x2)*F(S^(1<<x2))...+1; F(S)表示取状态为S的牌的期望次数,Sum表示什么都不取得概率,p(x1)表示的是取x1的概率,最后要加一因为有又多拿了一次.整理一下就可以了. 1 #include <cstdio> 2 const int Maxn=23; 3 double F[1<<Maxn],p[Maxn]; 4 int n; 5 int main() 6

Travel(HDU 4284状压dp)

题意:给n个城市m条路的网图,pp在城市1有一定的钱,想游览这n个城市(包括1),到达一个城市要一定的花费,可以在城市工作赚钱,但前提有工作证(得到有一定的花费),没工作证不能在该城市工作,但可以走,一个城市只能工作一次,问pp是否能游览n个城市回到城市1. 分析:这个题想到杀怪(Survival(ZOJ 2297状压dp) 那个题,也是钱如果小于0就挂了,最后求剩余的最大钱数,先求出最短路和 Hie with the Pie(POJ 3311状压dp) 送披萨那个题相似. #include <

POJ 1185 炮兵阵地 状压dp

http://poj.org/problem?id=1185 经典题目不必多说,直接贴代码. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 int n, m, cnt, size; 7 int a[110], st[70], ct[70]; 8 char str[15]; 9 int f[110][70][70]; 10 void init(

【Foreign】Number [状压DP]

Number Time Limit: 10 Sec  Memory Limit: 256 MB Description Input Output Sample Input 12345 5 Sample Output 24 HINT Solution 我们运用状压DP,令 f[j][opt] 表示当前余数为 j,状态为opt的方案. 状态记录的是:各个数字被用了几次. 那么我们就可以状压了.先DFS出每个状态,记sum[k]表示后缀积,那么显然 从 opt 转移到 第k个数字多用一次的状态 就是