题目:https://www.luogu.org/problemnew/show/P4660

   https://www.lydsy.com/JudgeOnline/problem.php?id=1168

  自己一开始有这样的想法:枚举一边的手套一定选到 S 集合,设 c = 选到 S 里每个手套的最小需要选的手套个数,则 c = 这边所有手套个数 - (S里个数最小的手套个数-1) 。

  设 ts = 另一边一定选到 S 集合里的至少一个手套的最小需要选的手套个数,则 ts = 不在 S 集合里的手套个数 + 1。

  对于各种情况取min,再换一下枚举“一定"和”至少“的两边。

  结果交到洛谷上只能得66分。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=,M=(<<)+,INF=2e9+;
int n,a[N],b[N],s0,s1,c[M],bin[N],ans=INF,prn;
void init()
{
bin[]=;
for(int i=;i<=n;i++)bin[i]=bin[i-]<<;
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++)scanf("%d",&a[i]),s0+=a[i];
for(int i=;i<=n;i++)scanf("%d",&b[i]),s1+=b[i];
init();
for(int s=;s<bin[n];s++)
{
int d=INF,c=;
for(int j=;j<=n;j++)
if(s&bin[j-])
{
if(!a[j]){c=INF;break;}
d=min(d,a[j]);
}
if(c)continue;
c=s0-d+;
int ts=;
for(int j=;j<=n;j++)
if(!(s&bin[j-]))ts+=b[j];
if(c+ts<ans)ans=c+ts,prn=c;
else if(c+ts==ans)prn=min(prn,c);
}
for(int s=;s<bin[n];s++)
{
int d=INF,c=;
for(int j=;j<=n;j++)
if(s&bin[j-])
{
if(!b[j]){c=INF;break;}
d=min(d,b[j]);
}
if(c)continue;
c=s1-d+;
int ts=;
for(int j=;j<=n;j++)
if(!(s&bin[j-]))ts+=a[j];
if(c+ts<ans)ans=c+ts,prn=ts;
else if(c+ts==ans)prn=min(prn,ts);
}
printf("%d\n%d\n",prn,ans-prn);
return ;
}

  想来是那个枚举一定选到 S 集合的时候限制太僵硬,多选了一些。

  然后得到了这个数据:

  4

  1 3 8 4

  1 1 4 9

  上面只要选13个,就一定会选到第一种或第二种;下面选2个一定会与上面重合。但在自己做法里不能体现。果然是那个地方限制得太僵硬。

  试图想一些修补措施。然后越想越觉得题解的思路好好,最后还是弃疗了自己原来的做法。

  题解是这样:设 ts 是对于集合 S 的,定义同上;则所有个数属于 [ S的颜色个数,在S里的手套个数 ] 的在另一边选择 x 个手套的答案 ans[ x ] 都要对 ts 取max,因为这些 x 可能取成 S 集合。

    这里的左边界可以直接认为是0。因为如果 x 比那个小,则取了不足 S 的集合,对应的 ts 一定更大,即答案一定更大,所以对这个取个max也无妨。

    然后似乎用单调队列来对那些 ans[ x ] 赋值?可以证明答案的 x 一定是 选一种颜色就全选了 +1 的那种个数,大约是从它对应的那个 ts 来看,则那个 +1 就是它和 ts 对上的那个颜色,其余颜色一定要选就全选,选的手套数更多。不过还是不太明白单调队列的原理。

  直到看了这个题解:http://blog.sina.com.cn/s/blog_76f6777d0101bchd.html,才豁然开朗。

  当然官方题解说得也是很明白的:b08.oi.edu.pl/downloads/booklet.pdf

  大概是一种颜色全给左边选上或全给右边选上,一共 2^n 种左边(x)/右边(y)的值,每个值可看作以 ( 0,0 ) 和 ( x,y ) 为两个端点的矩形;左边/右边选手套的个数在这个矩形(含边界)里的,就可以选成这种不相交的集合,从而是不合法的;如果不被任意一个矩形包含,就一定是合法的;画出来的话发现备选答案就是一堆拐角(也许要判一下与坐标轴的夹角处),所以按一维排序、另一维单调栈维护好所有矩形交的轮廓,就可以在那些拐角里找答案了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=,M=(<<)+,INF=2e9+;
int n,a[N],b[N],bin[N],top,na,nb,pra=INF,prb=INF;
struct Node{
int a,b;
bool operator< (const Node &v)const
{return a==v.a?b<v.b:a<v.a;}
}t[M],sta[M];
void init()
{
bin[]=;for(int i=;i<=n;i++)bin[i]=bin[i-]<<;
}
void updt(int ta,int tb)
{
if((ll)ta+tb<(ll)pra+prb)pra=ta,prb=tb;
else if((ll)ta+tb==(ll)pra+prb&&ta<pra)pra=ta,prb=tb;
}
int main()
{
int tp;
scanf("%d",&tp);
for(int i=;i<=tp;i++)scanf("%d",&a[i]);
for(int i=;i<=tp;i++)scanf("%d",&b[i]);
for(int i=;i<=tp;i++)
{
if(!a[i])nb+=b[i]; else if(!b[i])na+=a[i];
else a[++n]=a[i],b[n]=b[i];
}
init();
for(int s=;s<bin[n];s++)
{
for(int i=;i<=n;i++)
if(s&bin[i-])t[s].a+=a[i];
else t[s].b+=b[i];
}
sort(t,t+bin[n]);
for(int i=;i<bin[n];i++)
{
while(top&&t[i].b>=sta[top].b)top--;
sta[++top]=t[i];
}
for(int i=;i<=top;i++)
updt(sta[i-].a+,sta[i].b+);
updt(sta[top].a+,);
updt(,sta[].b+);
printf("%d\n%d\n",pra+na,prb+nb);
return ;
}

2018.10.30 一题 洛谷4660/bzoj1168 [BalticOI 2008]手套——思路!问题转化与抽象!+单调栈的更多相关文章

  1. 「洛谷5300」「GXOI/GZOI2019」与或和【单调栈+二进制转化】

    题目链接 [洛谷传送门] 题解 按位处理. 把每一位对应的图都处理出来 然后单调栈处理一下就好了. \(and\)操作处理全\(1\). \(or\)操作处理全\(0\). 代码 #include & ...

  2. 单调栈 && 洛谷 P2866 [USACO06NOV]糟糕的一天Bad Hair Day(单调栈)

    传送门 这是一道典型的单调栈. 题意理解 先来理解一下题意(原文翻译得有点问题). 其实就是求对于序列中的每一个数i,求出i到它右边第一个大于i的数之间的数字个数c[i].最后求出和. 首先可以暴力求 ...

  3. 【洛谷 P2900】 [USACO08MAR]土地征用Land Acquisition(斜率优化,单调栈)

    题目链接 双倍经验 设\(H\)表示长,\(W\)表示宽. 若\(H_i<H_j\)且\(W_i<W_j\),显然\(i\)对答案没有贡献. 于是把所有点按\(H\)排序,然后依次加入一个 ...

  4. 洛谷P3515 [POI2011]Lightning Conductor(动态规划,决策单调性,单调队列)

    洛谷题目传送门 疯狂%%%几个月前就秒了此题的Tyher巨佬 借着这题总结一下决策单调性优化DP吧.蒟蒻觉得用数形结合的思想能够轻松地理解它. 首先,题目要我们求所有的\(p_i\),那么把式子变一下 ...

  5. 洛谷 P7718 -「EZEC-10」Equalization(差分转化+状压 dp)

    洛谷题面传送门 一道挺有意思的题,现场切掉还是挺有成就感的. 首先看到区间操作我们可以想到差分转换,将区间操作转化为差分序列上的一个或两个单点操作,具体来说我们设 \(b_i=a_{i+1}-a_i\ ...

  6. [补题]找到原序列长度k的子序列中字典序最小的那个(单调栈)

    题意 题目如题,输入序列只包含小写字母,数据范围0<k<=len<=500000. 例: 输入:helloworld 输出:ellld 题解 使用单调栈.当已删掉n-k个字符,输出栈 ...

  7. 高精度加法——经典题 洛谷p1601

    题目背景 无 题目描述 高精度加法,x相当于a+b problem,[b][color=red]不用考虑负数[/color][/b] 输入输出格式 输入格式: 分两行输入a,b<=10^500 ...

  8. 2018.10.30 uoj#273. 【清华集训2016】你的生命已如风中残烛(组合数学)

    传送门 组合数学妙题. 我们把这mmm个数都减去111. 然后出牌的地方就变成了−1-1−1. 然后发现求出每个位置的前缀和之后全部都是非负数. 考虑在最后加入一个−1-1−1构成一个m+1m+1m+ ...

  9. 2018.10.30 bzoj4942: [Noi2017]整数(线段树压位)

    传送门 直接把修改的数拆成logloglog个二进制位一个一个修改是会TLETLETLE的. 因此我们把303030个二进制位压成一位储存在线段树里面. 然后维护区间中最靠左二进制位不为0/1的下标. ...

随机推荐

  1. NumPy入门基础【2】

    通用函数ufunc 一元ufunc举例: 1.abs.fabs:计算绝对值,fabs更快 2.sqrt:计算各元素的平方根,相当于arr0.5 3.square:计算各元素的平方根,相当远arr2 4 ...

  2. VS2010 fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏

    VS2010在经历一些更新后,建立Win32 Console Project时会出“error LNK1123” 错误,解决方案为将 项目|项目属性|配置属性|清单工具|输入和输出|嵌入清单 “是”改 ...

  3. EasyNVR、EasyDSS二次开发之:RTMP、HLS流在web页面进行无插件播放示例Demo代码

    不管是基于EasyNVR还是EasyDSS,都是支持无插件直播,这也是未来视频直播的一个趋势.对于传统的浏览器插件播放谁用谁知道: 以上是软件自带播放展示 背景需求 对于EasyNVR和EasyDSS ...

  4. 网站存储session的方案

    1: ASP.NET State Service是什么 用来管理 Session 的,正常来说,Session 位于IIS进程中(其实可以理解成在服务器的内存中),当IIS重启或程序池回收会自动清空S ...

  5. 九度OJ 1336:液晶屏裁剪 (GCD)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:983 解决:228 题目描述: 苏州某液晶厂一直生产a * b大小规格的液晶屏幕,由于该厂的加工工艺限制,液晶屏的边长都为整数.最近由于市场 ...

  6. 红米4A手机刷开发版rom并且获取root权限

    1 bl解锁 Critical partition flashing is not allowed就是因为没有bl解锁. 注册小米账号并且关联手机. 下载bl解锁工具 http://www.miui. ...

  7. Python菜鸟之路:Python基础-模块

    什么是模块? 在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护.为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,分组的规则就是把实现了某个 ...

  8. leetcode第一刷_Permutations

    生成全排列的经典问题.递归方法的典范. bool visited[10000]; void getPermutation(vector<int> &num, vector<v ...

  9. python多版本管理

    1.查看系统中的安装了那些python版本 2.查看系统中的alternatives命令是否安装 3.使用alternatives --install 接管python -install 选项使用了多 ...

  10. Ionic常见问题

    1.sh: 1: glxinfo: not found sudo apt-get update && sudo apt-get install mesa-utils 2.ionic s ...