练习赛 位运算 思维 思维
发布日期:2021-05-06 17:49:06 浏览次数:8 分类:技术文章

本文共 2561 字,大约阅读时间需要 8 分钟。

位运算
对lowbit理解更深了。。。
一开始没打表看看lowbit(i)的值是多少,就一直没明确的思路,后来打表发现 lowbit(i)的值一定是2的幂,从0开始的幂。一下子思路就清晰了,先存下来lowbit的值,以及每个lowbit值对应的 i(用队列存的),从lowbit值大的开始枚举。

可以不用写这么麻烦,直接for循环遍历一遍就行。打表可以发现lowbit(i)的值普遍比较小,而最大的值,在此前 i - 1个数的和也一定大于这个lowbit(i),较大值出现在后边, 我们选择从后向前遍历。

for(int i = limit; i >= 1; --i)
if( lowbit(i) > s) s -= lowbit(i);
我认为把所有的数存起来,然后从大往小遍历最合适。
因为 上边这个题的数列,即使出现最大的数,也不会大于前 i - 1个数的和。
但是如果不是呢?
例子: 1 1 1 100
我们求 102 是否可以写成某些数的和
如果从小到大遍历,会判断出 否
从大到小遍历,就可以成功判断
这种情况中,比较小的数选多了就没法选上比较大的数了

#include 
using namespace std;typedef long long ll;const int N = 1e5 + 9;ll s, l, sum[N];ll y[100];vector
v;struct num{ ll x; queue
pos;}a[N];ll lowbit(ll i){ return i & (-i);}int main(){ ios::sync_with_stdio(false); cin.tie(0); cin >> s >> l; for(int i = 1; i <= l; ++i) { a[lowbit(i)].x++, a[lowbit(i)].pos.push(i); //cout << lowbit(i) << endl; } int tmp = 16384;// 可以开到更大,不超过 N 就可以 // 第一次开的4096,wa了 while(s && tmp >= 1) { while(s >= tmp && a[tmp].x >0) { s-= tmp,a[tmp].x--; v.push_back(a[tmp].pos.front()); a[tmp].pos.pop(); } tmp >>= 1; } if(s) cout << -1 << endl; else { cout << v.size() << endl; for(int i = 0; i < v.size(); ++i) { if(i > 0) cout << " "; cout << v[i]; } cout << endl; } return 0;}

贪心。。。
不要将关注点放到part上
因为所有的连接管都需要移除,将关注点放到管子上的话,那么移除每个管子需要的就是连接的两个part中,值较小的一个

思维解法:
感觉很容易写错

#include
using namespace std;const int N = 1e5 + 9;int n, p, k;int a[N];int sum;int odd[N], even[N], od, ev;// 偶 + 偶 = 偶// 奇 + 奇 = 偶// 偶 + 奇 = 奇 int main(){ // p 个偶数部分 // k - p 个奇数 cin >> n >> k >> p; for(int i = 1; i <= n; ++i) { scanf("%d", &a[i]); if(a[i] & 1) odd[++od] = a[i]; else even[++ev] = a[i]; } if(od < k - p || (od - (k - p)) % 2 != 0 || ev + (od - (k - p)) / 2 < p ) { // 奇数不够 或者 剩下的奇数多一个 cout << "NO\n"; } else // 奇数够 并且 剩下的奇数个数是偶数 { // 我们把两个奇数看成一个偶数 cout << "YES\n"; int tmp = k - p; for(int i = 1; i <= tmp - 1; ++i) // 先少构造一个奇数 { printf("1 %d\n",odd[od--]); } for(int i = 1; i <= p - 1; ++i) // 少构造一个偶数 { if(ev) // 先用偶数构造 printf("1 %d\n",even[ev--]); else printf("2 %d %d\n",odd[od--],odd[od--]); } // 如果 tmp = 0 那么说明不用构造奇数,并且前边也没有构造奇数 所以if不用输出 // 至于要求为什么 p 也不能等于0 // 如果 p = 0,说明不用构造偶数,并且前边也没有构造偶数。 // 前边已经构造了 tmp - 1个奇数了,如果这个直接输出一个奇数 剩下的数并没有用完 // 所以这时候不输出这个,改成下边的输出,因为剩余的数里一定是奇数个奇数,直接输出全部就可以。 if(tmp && p) printf("1 %d\n", odd[od--]); cout << od + ev; while(od) printf(" %d",odd[od--]); while(ev) printf(" %d",even[ev--]); } return 0;}/*5 3 2 1 2 3 3 6 3 33 3 3 3 3 36 2 03 3 3 3 3 3*/

模拟解法:

上一篇:cf思维 专题1
下一篇:浙江省赛2021

发表评论

最新留言

表示我来过!
[***.240.166.169]2025年04月06日 06时26分40秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章