codeforces 888E Maximum Subsequence (折半枚举 双向搜索)
2017-11-19 20:09
441 查看
传送门:codeforces 888E
题目大意:
从大小为 n 的数组 a 中挑选出任意个元素,使得元素之和模 m 最大。
前置技能:
1.折半枚举。举个栗子,如果让你在 n 个数中找出 4 个数满足它们的和等于 sum。如果 n 很大的话四层循环会超时。这时就可以用折半枚举,也就是计算每两个数的和,然后从 2 个数之和中挑出 2 个满足题意的即可,只需要注意下标互不相同。
2.set集合的二分查找函数 upper_bound(),自然也有 lower_bound()。用法是 it = st.upper_bound(x); x为要查找的值,函数返回值为 set 的迭代器。upper_bound() 查找的是元素的最后一个可安插位置,也就是“
元素值 > 查找值 ”的第一个元素的位置。
思路:
对于每个元素来说,可取可不取,最多 35 个元素,共 2^35 种可能,直接枚举会超时。所以可以用折半枚举,每次计算一半的数组可以形成的值,并存入两个集合。然后枚一个集合的元素值,在另一个集合中二分搜索满足两者和 <m 的最大值,同时更新最大值。
为什么用集合是可以的呢?因为如果有两个相同的元素,说明取两者中的任意一个都可以。
代码:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
int n,m,a[40];
set<int> st1,st2;
set<int>:: iterator it,jt;
void dfs(int sum,int l,int r)
{ //用深搜进行搜索
if(l==r)
{ //当搜索完毕将产生的值插入集合并退出
if(r==n) st1.insert(sum);
else st2.insert(sum);
return;
}
dfs((sum+a[l])%m,l+1,r); //取当前元素
dfs(sum,l+1,r); //不取当前元素
}
int main()
{
int i,j,mx;
while(~scanf("%d%d",&n,&m))
{
for(i=0;i<n;i++) scanf("%d",&a[i]);
dfs(0,0,n/2); //枚举前半个数组可以产生的值
dfs(0,n/2,n); //枚举后半个数组可以产生的值
st1.insert(0); //插入0是为了防止某个集合中的元素已是最大的情况
st2.insert(0);
mx=0;
for(it=st1.begin();it!=st1.end();it++)
{ //枚举一个集合的值
jt=st2.upper_bound(m-1-*it); //在另一个集合二分搜索
jt--;
if(*it+*jt>mx) mx=*it+*jt; //更新最大值
}
printf("%d\n",mx);
}
return 0;
}
题目大意:
从大小为 n 的数组 a 中挑选出任意个元素,使得元素之和模 m 最大。
前置技能:
1.折半枚举。举个栗子,如果让你在 n 个数中找出 4 个数满足它们的和等于 sum。如果 n 很大的话四层循环会超时。这时就可以用折半枚举,也就是计算每两个数的和,然后从 2 个数之和中挑出 2 个满足题意的即可,只需要注意下标互不相同。
2.set集合的二分查找函数 upper_bound(),自然也有 lower_bound()。用法是 it = st.upper_bound(x); x为要查找的值,函数返回值为 set 的迭代器。upper_bound() 查找的是元素的最后一个可安插位置,也就是“
元素值 > 查找值 ”的第一个元素的位置。
思路:
对于每个元素来说,可取可不取,最多 35 个元素,共 2^35 种可能,直接枚举会超时。所以可以用折半枚举,每次计算一半的数组可以形成的值,并存入两个集合。然后枚一个集合的元素值,在另一个集合中二分搜索满足两者和 <m 的最大值,同时更新最大值。
为什么用集合是可以的呢?因为如果有两个相同的元素,说明取两者中的任意一个都可以。
代码:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
int n,m,a[40];
set<int> st1,st2;
set<int>:: iterator it,jt;
void dfs(int sum,int l,int r)
{ //用深搜进行搜索
if(l==r)
{ //当搜索完毕将产生的值插入集合并退出
if(r==n) st1.insert(sum);
else st2.insert(sum);
return;
}
dfs((sum+a[l])%m,l+1,r); //取当前元素
dfs(sum,l+1,r); //不取当前元素
}
int main()
{
int i,j,mx;
while(~scanf("%d%d",&n,&m))
{
for(i=0;i<n;i++) scanf("%d",&a[i]);
dfs(0,0,n/2); //枚举前半个数组可以产生的值
dfs(0,n/2,n); //枚举后半个数组可以产生的值
st1.insert(0); //插入0是为了防止某个集合中的元素已是最大的情况
st2.insert(0);
mx=0;
for(it=st1.begin();it!=st1.end();it++)
{ //枚举一个集合的值
jt=st2.upper_bound(m-1-*it); //在另一个集合二分搜索
jt--;
if(*it+*jt>mx) mx=*it+*jt; //更新最大值
}
printf("%d\n",mx);
}
return 0;
}
相关文章推荐
- POJ 2785 4 Values whose Sum is 0【双向搜索/折半枚举】
- 折半枚举(双向搜索)
- 折半枚举 双向搜索
- 160_折半枚举(双向搜索) 4 Values whose sum is 0 (POJ No.2785)
- poj 2785 4 Values whose Sum is 0(折半枚举(双向搜索))
- POJ 2785 4 Values whose Sum is 0 折半枚举(双向搜索)
- codeforces888e(折半枚举+二分搜索)
- codeforces 589C Polycarp's Masterpiece(分治 折半搜索)
- Codeforces 585D Lizard Era: Beginning | 折半搜索
- poj 3977 折半枚举二分搜索
- 2017年第0届浙江工业大学之江学院程序设计竞赛决赛 Problem E: qwb和李主席(折半搜索+类二分枚举)
- 折半枚举(双向搜索)
- POJ 3977 折半枚举+二分搜索
- CodeForces 372A Counting Kangaroos is Fun袋鼠口袋问题折半搜索
- LA --- 2965 Jurassic Remains 数相同的大写字母 【思维 + 状态压缩枚举 + 中途相遇法(折半搜索)】
- poj2785 折半枚举 双向查找
- CodeForces-920E Connected Components? 广度搜索 双向链表 判断联通 大量重复节点的删除
- 【POJ 2785 4 Values whose Sum is 0】+ 折半枚举(双项搜索))
- [Codeforces 585D] Lizard Era: Beginning (折半枚举)
- Codeforces 888E - Maximum Subsequence 折半枚举