[bzoj4874]筐子放球

时间:2022-08-28 18:24:30
来自FallDream的博客,未经允许,请勿转载,谢谢。

小N最近在研究NP完全问题,小O看小N研究得热火朝天,便给他出了一道这样的题目:
有 n 个球,用整数 1 到 n 编号。还有 m 个筐子,用整数1到m编号。
每个球只能放进特定的两个筐子之一,第 i 个球可以放进的筐子记为 Ai 和 Bi 。
每个球都必须放进一个筐子中。
如果一个筐子内有奇数个球,那么我们称这样的筐子为半空的。
求半空的筐子最少有多少个。
小N看到题目后瞬间没了思路,站在旁边看热闹的小I嘿嘿一笑:"水题!"
然后三言两语道出了一个多项式算法。
小N瞬间就惊呆了,三秒钟后他回过神来一拍桌子:
"不对!这个问题显然是NP完全问题,你算法肯定有错!"
小I浅笑:"所以,等我领图灵奖吧!"
小O只会出题不会做题,所以找到了你--请你对这个问题进行探究,并写一个程序解决此题
 
n,m<=200000
感觉是一道智商题 所以来做了做
想了半天只会一个log的做法
考虑线性基 每次有一个球可以选择a,b(a<b),就先把a的权值塔上1,然后加入只有a和b位是1的线性基
直接暴力插入是n^2,但是发现一个点出发的很多条边,在选择了一个基之后,假设基是u->v,那么u->其他点的边都变成了v->其他点的边,所以可并堆维护即可,复杂度nlogn
当然只有这道题才能满足线性基贪心
 
然后去搜了搜题解,发现答案就是有奇数条边的联通块个数 
因为偶数条边一定能满足两两配对 应该是可以证明的吧
所以直接dfs就行了 复杂度O(n)
线性基+可并堆
#include<iostream>
#include<cstdio>
#include<queue>
#define INF 2000000000
#define Dis(x) (x?x->dis:0)
#define MN 200000
using namespace std;
inline int read()
{
int x = , f = ; char ch = getchar();
while(ch < '' || ch > ''){ if(ch == '-') f = -; ch = getchar();}
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x * f;
} int n,m,s[MN+],to[MN+],ans=;
struct Tree
{
Tree *l,*r;int dis,x;
Tree(int k){dis=;x=k;l=r=NULL;}
int top(){return x;}
friend Tree* Merge(Tree*a,Tree*b)
{
if(!a) return b;
if(!b) return a;
if(a->x>b->x) swap(a,b);
a->r=Merge(a->r,b);
if(Dis(a->l)<Dis(a->r)) swap(a->l,a->r);
a->dis=Dis(a->r)+;
return a;
}
Tree* pop(){return Merge(l,r);}
Tree* ins(int x){return Merge(new Tree(x),this);}
}*rt[MN+]; int main()
{
m=read();n=read();
for(int i=;i<=n;i++) s[i]=,rt[i]=new Tree(INF);
for(int i=;i<=m;++i)
{
int x=read(),y=read();
if(x>y) swap(x,y);
s[x]^=;rt[x]=rt[x]->ins(y);
}
for(int i=;i<=n;++i)
{
while(rt[i]->top()==i) rt[i]=rt[i]->pop();
int x=rt[i]->top();
if(x==INF) continue;
to[i]=x;
rt[x]=Merge(rt[x],rt[i]);
}
for(int i=;i<=n;++i)
{
if(to[i]&&!s[i]) s[i]^=,s[to[i]]^=;
ans+=s[i];
}
cout<<n-ans<<endl;
return ;
}

靠谱做法

#include<iostream>
#include<cstdio>
#define getchar() (*S++)
#define MN 200000
char B[<<],*S=B;
using namespace std;
inline int read()
{
int x = ; char ch = getchar();
while(ch < '' || ch > '') ch = getchar();
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x;
} int head[MN+],ans=,sum=,cnt=,n,m;
struct edge{int to,next,w;}e[MN*+];
bool mark[MN+]; inline void ins(int f,int t)
{
e[++cnt]=(edge){t,head[f]};head[f]=cnt;
e[++cnt]=(edge){f,head[t]};head[t]=cnt;
} void dfs(int x)
{
mark[x]=;
for(int i=head[x];i;i=e[i].next,++sum)
if(!mark[e[i].to]) dfs(e[i].to);
} int main()
{
fread(B,,<<,stdin);
m=read();n=read();
for(register int i=;i<=m;++i) ins(read(),read());
for(register int i=;i<=n;++i)if(!mark[i])
{
sum=;dfs(i);
ans+=((sum/)&);
}
cout<<ans;
return ;
}

[bzoj4874]筐子放球的更多相关文章

  1. bzoj 4874&colon; 筐子放球

    4874: 筐子放球 Time Limit: 10 Sec  Memory Limit: 256 MB Description 小N最近在研究NP完全问题,小O看小N研究得热火朝天,便给他出了一道这样 ...

  2. 【bzoj4272】筐子放球

    看题解会的系列…… 详细解释先坑着,以后补…… #include<bits/stdc++.h> #define N 200005 using namespace std; ,tot=,cn ...

  3. 放球游戏B

    题目描述 校园里在上活动课,Red和Blue两位小朋友在玩一种游戏,他俩在一排N个格子里,自左到右地轮流放小球,每个格子只能放一个小球.第一个人只能放1个球,之后的人最多可以放前一个人的两倍数目的球, ...

  4. 【题解】放球游戏B

    题目描述 校园里在上活动课,Red和Blue两位小朋友在玩一种游戏,他俩在一排N个格子里,自左到右地轮流放小球,每个格子只能放一个小球.第一个人只能放1个球,之后的人最多可以放前一个人的两倍数目的球, ...

  5. 【题解】放球游戏A

    题目描述 校园里在上活动课,Red和Blue两位小朋友在玩一种游戏,他俩在一排N个格子里,自左到右地轮流放小球,每个格子只能放一个小球.每个人一次只能放1至5个球,最后面对没有空格而不能放球的人为输. ...

  6. COGS396&period; &lbrack;网络流24题&rsqb;魔术球问题(简化版

    问题描述: 假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为 1,2,3,4......的球. (1)每次只能在某根柱子的最上面放球. (2)在同一根柱子中,任何2个相邻球的编号之和为完全平 ...

  7. C&num;之桶中取黑白球问题

    <编程之美>284页,问题4.6:桶中取黑白球. 有一个桶,里面有白球.黑球各100个,人们必须按照以下规则把球取出来: 1. 每次从桶中拿两个球: 2. 如果两球同色,再放入一个黑球: ...

  8. cogs&lowbar;396&lowbar;魔术球问题&lowbar;&lpar;最小路径覆盖&plus;二分图匹配&comma;网络流24题&num;4&rpar;

    描述 http://cojs.tk/cogs/problem/problem.php?pid=396 连续从1开始编号的球,按照顺寻一个个放在n个柱子上,\(i\)放在\(j\)上面的必要条件是\(i ...

  9. 【网络流24题】No&period;4 魔术球问题 (二分&plus;最小路径覆盖)

    [题意] 假设有 n 根柱子, 现要按下述规则在这 n 根柱子中依次放入编号为 1, 2, 3, ¼的球.( 1)每次只能在某根柱子的最上面放球.( 2)在同一根柱子中,任何 2 个相邻球的编号之和为 ...

随机推荐

  1. 爱上MVC~在Views的多级文件夹~续~分部页的支持

    回到目录 之前写的一篇文章,主要针对View视图,它可以放在N级目录下,不必须非要在views/controller/action这种关系了,而在程序运行过程中,发现分页视图对本功能并不支持,原因很简 ...

  2. Python基础(9)--正则表达式

    正则表达式是一个很有用的工具,可处理复杂的字符匹配和替换工作.在Python中内置了一个re模块以支持正则表达式. 正则表达式有两种基本的操作,分别是匹配和替换. 匹配就是在一个文本字符串中搜索匹配一 ...

  3. 移动Web单页应用开发实践——实现Pull to Request(上&sol;下拉请求操作)

    在单页应用开发中,无论是页面结构化,还是Pull to Request,都离不开一个技术——页面局部滚动.当下的移动web技术,主要使用下面两种方式实现局部区域的滚动: 基于IScroll组件,也有很 ...

  4. JDK的dt&period;jar和Java BeanInfo接口

    在JAVA_HOME/lib以下有两个比較重要的jar文件.tools.jar和dt.jar. tools.jar在上篇文章中做了简单的介绍.这里来介绍下dt.jar. 在Oracle官方站点搜dt. ...

  5. 求N&excl;末尾的0的个数(找规律&plus;递归)

    0\'s Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描写叙述 计算整数n!(n的阶乘)末尾有多少个0. 输入 第一行输入一个数T代 ...

  6. 抓包分析YY音频

    YY的音频数据传输是P2P协议,音频的编码为AAC,下面抓去的音频编码的信息和频谱信息. 音频编码为AAC,采样为44K,码率24kb/s.音频编码在24kb/s码率能达到15K的音质.值得大家学习啊 ...

  7. 使用cordova开发app

    前言 公司之前用的app就是一个套壳挂个链接就能用的app,后来需要添加微信分享方便传播,没办法只好做成混合式的app了, 因为之前做.net用vs可以创建cordova项目也试着玩过,就决定用cor ...

  8. 如何修改hosts文件

     如何修改hosts文件 1.进入路径 C:\Windows\System32\drivers\etc 2.拷贝hosts文件到其他地方3.修改拷贝的hosts文件,右键用记事本打开4.直接修改或添加 ...

  9. 微信小程序----用户拒绝授权&comma;重新调起授权

    获取用户信息 wx.getUserInfo({ withCredentials: true, success: function (res) { var nickName = res.userInfo ...

  10. 时区提示:Local time zone must be set--see zic manual page 2018的解决办法

    问题描述:在centos服务器上执行date命令时,显示的时间信息中的时区不正常,如下: [root@ulocalhost ~]# date Mon Apr 9 02:57:38 Local time ...