HDU 5076 Memory

Memory

Time Limit: 4000ms

Memory Limit: 262144KB

This problem will be judged on HDU. Original ID: 5076
64-bit integer IO format: %I64d      Java class name: Main

Special Judge

Little Bob’s computer has 2n bytes of memory. For convenience, n-bit integers 0 to 2n - 1 are used to index these bytes.

Now he wants to assign a value to each byte of the memory. In this problem, a byte is composed of m bits. Therefore he can only assign 0 to 2m - 1 (inclusive) to a single byte.

Bob has some preferences on which value to be assigned to each byte. For the byte indexed by i, if it is assigned with value j (0 ≤ j < 2m), the preference score for it is wi,j.

In addition, each byte has a threshold value. For two different bytes indexed by a and b, if the following two conditions are satisfied, there will be an additional score (ua xor ub):

1.a and b only have one bit of difference in their binary forms;

2.The assigned value of byte a is not less than its threshold value, or the assigned value of byte b is not less than its threshold value.

The total score of an assignment solution is the sum of the preference scores of all bytes plus the sum of all additional scores.

Bob wants to find an assignment solution with the maximum total score. If there are multiple solutions, you can output any of them.

Input

The first line contains an integer T (T ≤ 3), denoting the number of the test cases.

For each test case, the first line contains two integers, n and m(1 ≤ n, m ≤ 8), as mentioned above. The second line contains 2n integers, and the i-th integer is the threshold value for byte i. The threshold values are between 0 and 2m - 1, inclusively. The third line contains 2n integers, and the i-th integer is ui(0 ≤ ui < 1024). The next 2n lines give all preference scores. Each line contains 2m integers, and the j-th integer of the i-th line is wi,j (-1024 ≤ wi,j < 1024).

Output

For each test case, output one line consisting of 2n integers between 0 and 2m - 1, and the i-th integer is the value assigned to byte i in the assignment solution with the maximum total score.

Sample Input

1
3 2
0 1 1 3 3 0 3 3
4 8 8 7 0 9 2 9
-9 -8 3 2
-9 -6 4 1
-6 -8 -5 3
3 -1 -4 -1
-6 -5 1 10
-10 7 3 -10
-3 -10 -4 -5
-2 -1 -9 1

Sample Output

2 2 3 0 3 1 0 3

Source

2014 Asia AnShan Regional Contest

解题:网络流

  1. 对于每个位置拆成两个点,左边源右边汇。
  2. 如果这个位置的index有奇数个1,左边连小于的w,右边连大于等于的w。
  3. 如果这个位置的index有偶数个1,左边连大于等于的w,右边连小于的w。
  4. 每个位置左边往右边连一条inf的弧,代表这两个点不能都不割。
  5. 对于每组a,b,从奇数的小于连向偶数的小于,ua xor ub。
  6. 为了避免负流量可以把所有w加一个1024,不影响最后结果。
  7. 总之建出来是个二分图。
  8. 最后建完就可以发现其实可以不用拆点,但拆了还是更好理解一些。

最后所有的收益加起来减掉最小割就是最大收益。

据说上面是昂神分析的

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 const int INF = ~0U>>2;
  4 const int maxn = 1024;
  5 struct arc {
  6     int to,flow,next;
  7     arc(int x = 0,int y = 0,int z = -1) {
  8         to = x;
  9         flow = y;
 10         next = z;
 11     }
 12 } e[maxn*maxn];
 13 int head[maxn],d[maxn],cur[maxn],tot,S,T;
 14 void add(int u,int v,int flow) {
 15     e[tot] = arc(v,flow,head[u]);
 16     head[u] = tot++;
 17     e[tot] = arc(u,0,head[v]);
 18     head[v] = tot++;
 19 }
 20 bool bfs() {
 21     queue<int>q;
 22     memset(d,-1,sizeof d);
 23     d[S] = 1;
 24     q.push(S);
 25     while(!q.empty()) {
 26         int u = q.front();
 27         q.pop();
 28         for(int i = head[u]; ~i; i = e[i].next) {
 29             if(e[i].flow && d[e[i].to] == -1) {
 30                 d[e[i].to] = d[u] + 1;
 31                 q.push(e[i].to);
 32             }
 33         }
 34     }
 35     return d[T] > -1;
 36 }
 37 int dfs(int u,int low) {
 38     if(u == T) return low;
 39     int a,tmp = 0;
 40     for(int &i = cur[u]; ~i; i = e[i].next) {
 41         if(e[i].flow &&d[e[i].to] == d[u]+1&&(a=dfs(e[i].to,min(low,e[i].flow)))) {
 42             e[i].flow -= a;
 43             e[i^1].flow += a;
 44             low -= a;
 45             tmp += a;
 46             if(!low) break;
 47         }
 48     }
 49     if(!tmp) d[u] = -1;
 50     return tmp;
 51 }
 52 int dinic(int ret = 0) {
 53     while(bfs()) {
 54         memcpy(cur,head,sizeof cur);
 55         ret += dfs(S,INF);
 56     }
 57     return ret;
 58 }
 59 int U[maxn],Th[maxn],B[maxn],L[maxn],ans[maxn],Bid[maxn],Lid[maxn];
 60 int main() {
 61     int kase,n,m;
 62     scanf("%d",&kase);
 63     while(kase--) {
 64         scanf("%d%d",&n,&m);
 65         n = (1<<n);
 66         m = (1<<m);
 67         for(int i = tot = 0; i < n; ++i)
 68             scanf("%d",Th + i);
 69         for(int i = 0; i < n; ++i)
 70             scanf("%d",U + i);
 71         for(int i = 0; i < n; ++i) {
 72             B[i] = L[i] = -1;
 73             for(int j = 0,w; j < m; ++j) {
 74                 scanf("%d",&w);
 75                 w += 1024;
 76                 if(j >= Th[i] && B[i] < w) {
 77                     B[i] = w;
 78                     Bid[i] = j;
 79                 } else if(L[i] < w) {
 80                     L[i] = w;
 81                     Lid[i] = j;
 82                 }
 83             }
 84         }
 85         S = n<<1;
 86         T = S + 1;
 87         memset(head,-1,sizeof head);
 88         for(int i = 0; i < n; ++i) {
 89             int k = __builtin_popcount(i);
 90             add(i,i + n,INF);
 91             if(k&1) {
 92                 add(S,i,L[i]);
 93                 add(i + n,T,B[i]);
 94             } else {
 95                 add(S,i,B[i]);
 96                 add(i + n,T,L[i]);
 97             }
 98             for(int j = i + 1; j < n; ++j) {
 99                 if(__builtin_popcount(i^j) == 1) {
100                     if(k&1) add(i,j + n,U[i]^U[j]);
101                     else add(j,i + n,U[i]^U[j]);
102                 }
103             }
104         }
105         dinic();
106         for(int i = 0; i < n; ++i) {
107             if(i) putchar(‘ ‘);
108             if(__builtin_popcount(i)&1)
109                 printf("%d",(~d[i])?Lid[i]:Bid[i]);
110             else printf("%d",(~d[i])?Bid[i]:Lid[i]);
111         }
112         putchar(‘\n‘);
113     }
114     return 0;
115 }

时间: 2024-09-29 15:30:55

HDU 5076 Memory的相关文章

HDU 2871 Memory Control(线段树)

HDU 2871 Memory Control 题目链接 题意:内存操作,和hotel那题差不多,多一个get操作 思路:线段树区间合并,其他都差不多,多一个get操作,这个用set去乱搞就过了- -,估计数据鶸吧,多这个操作感觉要用splay去搞了 代码: #include <cstdio> #include <cstring> #include <algorithm> #include <set> using namespace std; const i

HDU 2871 Memory Control

一共4种操作 其中用线段树 区间合并,来维护连续空的长度,和找出那个位置.其他用vector维护即可 #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> #include <iostream> #include<vector> #define lson i<<1 #define rson i<<1|1 #define N

hdu 2871 Memory Control(线段树)

题目链接:hdu 2871 Memory Control 题目大意:模拟一个内存分配机制. Reset:重置,释放所有空间 New x:申请内存为x的空间,输出左地址 Free x:释放地址x所在的内存块 Get x:查询第x个内存块,输出左地址 解题思路:一开始全用线段树去做,写的乱七八糟,其实只要用线段树维护可用内存.然后用户一个vector记录所有的内存块. #include <cstdio> #include <cstring> #include <vector>

HDU 2871 Memory Control (线段树,区间合并)

http://acm.hdu.edu.cn/showproblem.php?pid=2871 Memory Control Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4418    Accepted Submission(s): 1056 Problem Description Memory units are numbered

HDU 2871 Memory Control(线段树&#183;区间合并&#183;Vector)

题意  模拟内存申请  有n个内存单元  有以下4种操作 Reset  将n个内存单元全部清空 New x  申请一个长度为x的连续内存块  申请成功就输出左端 Free x  将x所在的内存块空间释放  释放成功输出释放的内存始末位置 Get x  输出第x个内存块的起始位置 Reset 和 New 都是基本的区间合并知识  比较简单  Free和Get需要知道内层块的位置  所以我们在New的时候要将申请的内存块的始末位置都存起来  两个内层块不会相交  这样就能通过二分找到需要的内层块了

hdu 2871 Memory Control(成段更新,区间合并)

这道题在网上搜了一下题解,别人说是比hdu hotel还要变态的一题. 既然是变态题,因为它综合了线段树的几乎所有操作. 这道题的题意是: 有如下几个操作: 1:首先是Reset操作,这个操作代表的是把所有的内存空间全部都清空. 2:New x:代表的是分配一个x个内存空间,如果有内存空间的话,则输出那个内存空间的最左边的那个端点.否则,则输出Reject New 3:Free x:代表的是释放含有x这个数的内存空间.如果这个内存空间已经被释放了,那么就输出Reject Free 4:Get x

hdu 5076 最小割灵活的运用

题意比较复杂,其实关键是抽象出来:每个点,可以赋予俩个值(二选一,必需选一个,设ai,bi).  求所有之和最大,有条件:若俩个点同时满足: 1,:点的二进制只有一位不同.  2:至少有一个是选B值: 则可获得对应加成. 这题开始想了半天,建图遇到问题,看了官方说是最小割,于是入手: a值就是小于阈值的最大值,B值就是大于等于的最大值. 思路:俩个点选其一,必然想到建二分(每个点一分为二)图,中间连无穷的边.因为只有一位不同,必然分奇偶点,有奇数个1的点,源点到他为A值,对应点到汇点为B值,偶点

HDU 2871&quot;Memory Control&quot;(线段树区间和并+set&lt;pii &gt;.lower_bound())

传送门 •题意 有 n 个内存单元(编号从1开始): 给出 4 种操作: (1)Reset :表示把所有的内存清空,然后输出 "Reset Now". (2)New x :表示申请一块长度为 x 的内存块(满足起始地址尽可能小): 如果找到,输出 "New at A",A表示该内存块的起点,找不到,输出 "Reject New". (3)Free x :表示把包含第 x 块单位内存的内存块清除: 如果 x 在某内存块中,输出 "Free

线段树题目汇总

区间合并部分: POJ 3667 Hotel 求某大于等于a的最长区间 #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #define LEN 50001<<2 using namespace std; struct Line_tree { //分别表示以当前区间为左端点的最长连续空白区间,为右端点的最长连续空白区间,该区间的最长连续空白区