HDU 4317 位运算

【题意】:

在一个常规的NIM游戏里,你可以在每堆石子拿走任意数量的石子,问求使先手必败的情况下拿走石子数量的最小值。

【知识点】:

位运算,DP

【题解】:

一道精致的位运算的好题目,细节有不少。

具体解释在代码内。

【代码】:

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <cmath>
 5 #include <cstdlib>
 6 #include <climits>
 7 #include <algorithm>
 8
 9 #define wh while
10 #define sf scanf
11 #define pf printf
12 #define clr(abc,z) memset(abc,z,sizeof(abc))
13 #define FOR0(i, n) for(int i = 0; i < n; i++)
14 #define FOR1(i, n) for(int i = 1; i <= n; i++)
15
16 using namespace std;
17
18 const int maxb = 1 << 11;
19 const int maxn = 25;
20
21 int dp[maxn][maxb], s[maxn], a[maxn], t[maxb];
22 int n;
23 int getbit(int x){
24     int ret = 0;
25     wh(x){
26         ret += (x & 1); x >>= 1;
27     }
28     return ret;
29 }
30
31 int main(){
32     FOR0(i, maxb) t[i] = getbit(i);
33     wh(sf("%d", &n) != EOF){
34         FOR0(i, n) sf("%d", &a[i]);
35         if(n < 2){
36             puts("impossible"); continue;
37         }
38         int m, ans;
39         clr(s, 0);
40         FOR1(i, maxn - 1){
41             FOR0(j, n)
42                 if(a[j] & (1 << (i - 1))) s[i - 1] |= (1 << j);
43             if(s[i - 1]) m = i + 1;
44         }
45         clr(dp, 0x3f); ans = dp[0][0]; dp[0][0] = 0;
46         //dp[i][k]从右往左第i+1位通过第i位进位得到的1的状态情况
47         FOR1(i, m){
48             FOR0(j, (1 << n)){
49                 if(dp[i - 1][j] < ans){
50                     int tmp = j & s[i - 1]; //j代表进位后得到的位状况
51                                             //s[i - 1]保存原本存在的当前位置的1的状况
52                     for(int k = tmp; k < (1 << n); k++){
53                         if(((k & tmp) == tmp)
54                            //经过右边位置进位得到的状态存在与总状态中
55                        && (((s[i - 1] ^ j) & (k ^ tmp)) == (k ^ tmp))
56                            //未经进位得到的状态存在于右边位置中1状态子集内
57                        && (((t[(s[i - 1] ^ j) ^ (k ^ tmp)] & 1) == 0) || t[(s[i - 1] ^ j) ^ (k ^ tmp)] < n))
58                            //那些右边状态不进位加1的状态不能包含所有的1
59                             dp[i][k] = min(dp[i][k], dp[i - 1][j] + (t[k ^ tmp] + (t[(s[i - 1] ^ j) ^ (k ^ tmp)] & 1)) * (1 << (i - 1)));
60                     }
61                 }
62             }
63         }
64         FOR0(i, (1 << n)){
65             if((t[i] & 1) == 0)
66                 ans = min(ans, dp[m][i]);
67         }
68         pf("%d\n", ans);
69     }
70     return 0;
71 }

时间: 2024-09-30 06:30:13

HDU 4317 位运算的相关文章

HDU - 2276 位运算矩阵快速幂

挺有意思的一道题 要会运用一些常见的位运算操作进行优化 题目的本质就是要求下面的式子 \(dp[i][j+1]=(dp[i-1][j]+dp[i][j]) mod 2\) (第\(i\)个字符在\(j\)秒时的状态,1要特判) 对于1与0的乘法运算其实与&一致 (按道理OJ应该自己会优化的吧..) /*H E A D*/ struct Matrix{ ll mt[111][111],r,c; void init(int rr,int cc,bool flag=0){ r=rr;c=cc; mem

hdu 1882 Strange Billboard(位运算+枚举)

http://acm.hdu.edu.cn/showproblem.php?pid=1882 感觉非常不错的一道题. 给一个n*m(1<=n,m<=16)的矩阵,每一个格子都有黑白两面,当翻一个格子时,它的上下左右都要翻转,问最后使格子全变为白色的最少翻转步数. 仅仅需枚举第一行的状态即可,由于对于第i(i>=2)行j列翻转情况受上一行的制约,仅仅有当上一行也是'X'的时候,该行j列才干翻转,使i-1行j列变为'.',否则i行j列不能翻转.依次进行下去,当最后一行全变为白色,说明翻转成功

HDU 5023 A Corrupt Mayor&#39;s Performance Art(线段树+优美的位运算)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5023 Problem Description Corrupt governors always find ways to get dirty money. Paint something, then sell the worthless painting at a high price to someone who wants to bribe him/her on an auction, this

HDU 2276 Kiki &amp; Little Kiki 2 (位运算+矩阵快速幂)

HDU 2276 Kiki & Little Kiki 2 (位运算+矩阵快速幂) ACM 题目地址:HDU 2276 Kiki & Little Kiki 2 题意: 一排灯,开关状态已知,每过一秒:第i个灯会根据刚才左边的那个灯的开关情况变化,如果左边是开的,它就会变化,如果是关的,就保持原来状态.问m秒后的状态. 第1个的左边是最后一个. 分析: 转移不好想啊... 变化是这样的: 原来 左边 变化 1 1 0 1 0 1 0 1 1 0 0 0 然后想到 (~原来)^(左边)=变化

HDU 1882 Strange Billboard(位运算)

题目链接 题意 : 给你一个矩阵,有黑有白,翻转一个块可以让上下左右都翻转过来,问最少翻转多少次能让矩阵变为全白. 思路 : 我们从第一行开始枚举要翻转的状态,最多可以枚举到2的16次方,因为你只要第一行的确定了,第二行要翻转的也就确定了,所以第一行的状态决定了最后的状态.看了网上大神,真是让位运算废了啊,,,,,太复杂了...... 1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #

hdu 2721(字符串处理,位运算 暴力)

Persistent Bits Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 201    Accepted Submission(s): 116 Problem Description WhatNext Software creates sequence generators that they hope will produce

hdu 3257 Hello World!(位运算 &amp; 模拟)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3257 Hello World! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 476    Accepted Submission(s): 180 Problem Description Your task is to print ...

hdu 5344 (多校联赛) MZL&#39;s xor --- 位运算

here:    首先看一下题吧:题意就是让你把一个序列里所有的(Ai+Aj) 的异或求出来.(1<=i,j<=n) Problem Description MZL loves xor very much.Now he gets an array A.The length of A is n.He wants to know the xor of all (Ai+Aj)(1≤i,j≤n) The xor of an array B is defined as B1 xor B2...xor B

HDU 4825 Xor Sum 字典树+位运算

点击打开链接 Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) Total Submission(s): 291    Accepted Submission(s): 151 Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus