解题:POI 2008 Subdivision of Kingdom

题面

还可以这么搜......学到了(PoPoQQQ orz)

我们最朴素的做法是枚举所有状态(当然可以剪,剪完最终实际状态量也是$C_{26}^{13}$的),然后每次$O(n)$扫一遍判断,大概会T炸,考虑优化

我们先预处理每个状态中$1$的数目和连边的状态,然后压缩状态初始让一边集合为空,一边集合为全集,这样每次从已有的点的前面$\frac{n}{2}$个点中枚举一个加入另一边,就可以边搜边更新边数而不用最后$O(n)$检查了。另一个问题是数组可能非常大,这里我们可以把状态拆成前后两半,然后检查的时候检查两半再拼起来就好了。学了学技巧和思想还是挺好的说......

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 int ss[28],cnt[1<<13];
 6 int n,m,t1,t2,ans=2e9,anss,num,half;
 7 int s(int x)
 8 {
 9     return 1<<(x-1);
10 }
11 int getst(int x)
12 {
13     return cnt[x&half]+cnt[x>>num];
14 }
15 void DFS(int last,int noww,int state,int numb)
16 {
17     if(noww>n) return ;
18     if(noww==num)
19     {
20         if(numb<ans)
21             ans=numb,anss=state;
22         return ;
23     }
24     for(int i=last;i<=n;i++)
25         DFS(i+1,noww+1,state|s(i),numb-getst(state&ss[i])+getst((~state)&ss[i]));
26 }
27 int main ()
28 {
29     scanf("%d%d",&n,&m);
30     num=n>>1,half=(1<<num)-1;
31     for(int i=1;i<=m;i++)
32     {
33         scanf("%d%d",&t1,&t2);
34         ss[t1]|=s(t2),ss[t2]|=s(t1);
35     }
36     for(int i=1;i<=half;i++)
37         cnt[i]=cnt[i>>1]+(i&1);
38     DFS(1,0,0,0);
39     for(int i=1;i<=n;i++)
40         if(anss&s(i)) printf("%d ",i);
41     return 0;
42 }

原文地址:https://www.cnblogs.com/ydnhaha/p/9781214.html

时间: 2024-10-10 07:39:45

解题:POI 2008 Subdivision of Kingdom的相关文章

[POI 2008][BZOJ 1132]Tro

这题我真是无能为力了 这题的做法还是挺简单的 枚举左下角的点做为原点,把其余点按极角排序    PS.是作为原点,如枚举到 k 时,对于所有 p[i] (包括p[k]) p[i]-=p[k] (此处为向量减法) 排序后满足 i<j 的两个向量 p[i] 和 p[j] 的叉积都是正数了 ΣΣp[i]×p[j] = ΣΣ(p[i].x*p[j].y-p[i].y*p[j].x) = Σ(p[i].x*Σp[j].y)-Σ(p[i].y*Σp[j].x) 计算叉积和的复杂度就从 O(n2) 降为了 O

[POI 2008]Mafia

这题目写了我好长时间,但还是几乎(不要在意细节)一遍 A 了喵~ 据说有代码奇短的,Orz 思路巧妙的大爷 想我这种 Brute Force 写写的傻 X 真是代码量飞起来了耶,喵~ 如果把每个人看成点,每个人要 kill 的人向此人连出一条有向边,那么每个点仅有一条出边和一条入边 经验告诉我们,这就是 环+内向图 的节奏 经验又告诉我,处理这种图要么先暴力搞环,再搞挂在环上的树.要么先搞树,再弄环. 此题显然是后者 环+内向图只需要用 bfs 就可以搞出来了,看到写 tarjan 的真是 Or

BZOJ 1132 POI 2008 Tro 计算几何

题目大意:给出平面上的一些点,问这些点中的任意三个点组成的三角形的面积和是多少. 思路:看数据范围只算法系列.由于每个三角形有三个顶点,因此暴力的话应该是O(n^3)的时间复杂度,很明显超时了,但是我们只需要将它优化到O(n^2logn)就可以解决了. 好吧,剩下的随便猜一猜,比如O(n^2)的枚举,然后剩下的logn什么也干不了... 再比如O(n)的枚举,然后剩下O(nlogn)排序... 好像有戏啊.. 枚举每一个点,计算以这个点为坐标原点,在第一象限的所有点与原点组成的三角形的面积和.计

[POI 2008&amp;洛谷P3467]PLA-Postering题解(单调栈)

Description Byteburg市东边的建筑都是以旧结构形式建造的:建筑互相紧挨着,之间没有空间.它们共同形成了一条长长的,从东向西延伸的建筑物链(建筑物的高度不一). Byteburg市的市长Byteasar,决定将这个建筑物链的一侧用海报覆盖住.并且想用最少的海报数量,海报是矩形的. 海报与海报之间不能重叠,但是可以相互挨着(即它们具有公共边),每一个海报都必须贴近墙并且建筑物链的整个一侧必须被覆盖(意思是:海报需要将一侧全部覆盖,并且不能超出建筑物链) 输入格式:第一行为一个整数n

bzoj 1112 poi 2008 砖块

这滞胀题调了两天了... 好愚蠢的错误啊... 其实这道题思维比较简单,就是利用treap进行维护(有人说线段树好写,表示treap真心很模板) 就是枚举所有长度为k的区间,查出中位数,计算代价即可. (根据绝对值不等式的几何意义,中位数一定是最优解) 而维护长度为k的区间也很简单,就是首先把前k个扔到树上,然后每次把新来的插入,把最前面的一个删除即可 至于求中位数,简直就是基础操作嘛 关键在于...代价怎么算? 显然我们不能把所有数枚举出来挨个加减,这样会T飞的... 所以我们考虑直接在tre

浅谈单调栈的实现方式和简单应用

一.单调栈的原理和实现方式 1.定义 从栈底元素到栈顶元素呈单调递增或单调递减,栈内序列满足单调性的栈: 2.原理 (1)当新元素在单调性上优于栈顶时(单增栈新元素比栈顶大,单减栈新元素比栈顶小),压栈,栈深+1: (2)当新元素在单调性与栈顶相同(新元素于栈顶相同)或劣于栈顶时(单增栈新元素比栈顶小,单减栈新元素比栈顶大),弹栈,栈深-1: 3.一般实现形式 以单增栈(栈顶为最大值)为例: n为元素数,h为入栈序列,tot为栈深,stack为单增栈: void stacks(){ int st

Poi 2014 解题报告( 1 - 4 ,6 )

撸了一下Poi 2014 ,看了一下网上题解不多,所以决定写一下.有的题应该是数据不强水过去了,等北京回来在写一下复杂度比较靠谱的代码 o(╯□╰)o 第一题: 题意是给定一个长度不大于1000000,只包括p和j的串,求一个最长的子串,要求子串任何一个前缀和后缀都满足p的数量不少于j的数量. 首先把p当做1,把j当做0,算出前缀和 sum[] ,原来的问题就转化为求一个最长区间 [l,r] ,使得任意的i∈[l,r],都有 sum[i] - sum[l-1] >= 0 并且 sum[r] -

解题:POI 2013 Triumphal arch

题面 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=300005; 6 int n,t1,t2,cnt,l,r,mid,ans; 7 int p[N],noww[2*N],goal[2*N]; 8 int son[N],dp[N]; 9 void link(int f,int t) 10 { 11 noww[++cnt]=

解题:POI 2010 Beads

题面 正反各做一遍哈希来判断,然后在两个哈希值里取一个$max/min$做哈希值,然后每次把子串们的哈希插进$set$里,最后统计集合大小,就可以优秀地在$O(nlog^2$ $n)$中出解了 然后我觉得这样太没有理想了,就写了一个挂链哈希表,结果跑的贼慢... 我挂链时的区分方法是换模数再模出一个新值,然后这样做的时候注意要和哈希表的基数和模数区分开 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm>