zoukankan      html  css  js  c++  java
  • P2114 [NOI2014]起床困难综合症

    题目地址

    经典状态压缩题,思路挺巧妙的。(也可能是我太蒻了吧)、、、

    题解

    我们要从 ([0-m]) 中间选一个数 (x_0) 使得最后的攻击力最大。

    如果从二进制的角度来观察 (x_0) ,你就会发现一系列的 ( ext{xor})(&)(|) 操作只不过是 (x_0) 二进制下的每一位在进行这一系列操作,使得最后的答案最大。

    “换言之,对于任意的 k(0<=k<=30),‘ans 的第 k 位是几’只与‘ (x_0) 的第 k 位是几’有关”

    于是考虑二进制下填位的方法,从高位到低位依次填 (1)(0)

    (x_0)(k) 位上填 1 ,当且仅当

    • (x_0)(k) 位上填 1 ,值不会超过 (m)

    • (x_0)(k) 位上填 1 比填 0 要优

    知道什么时候太填 (1) 什么时候填 (0),你就可以轻轻松松切掉这道题了。

    Code

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1e5+7;
    int n,m;
    int t[N];
    string op[N];
    inline int calc(int k,int now) {
    	for(int i=1;i<=n;++i) {
    		int x = (t[i]>>k) & 1;
    		if(op[i] == "AND") now &= x;
    		else if(op[i] == "OR") now |= x;
    		else now ^= x;
    	}
    	return now;
    }	//运算n次后看返回 1 还是 0 
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;++i) {
    		char str[5];
    		scanf("%s%d",str,&t[i]); op[i] = str;
    	}
    	int val = 0 ,ans = 0;	//ans来保存最后攻击力 
    	for(int i=29;i>=0;--i) {	//位运算学着学着就从零开始计数了qwq 
    		int res0 = calc(i,0) ,res1 = calc(i,1);	//分别处理看一下填0和填一会怎么样
    		if(val+(1<<i)<=m && res0<res1)
    			val += (1<<i) ,ans += (res1<<i);
    		else
    			ans += (res0<<i);
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    

    刚刚看了一下洛谷题解,发现题解的大佬们都吊打我,还说这是一道大水题。

  • 相关阅读:
    自定义拦截器
    MVP模式网络请求购物车
    mvp+RecyclerView实现网络请求
    二维码扫描
    进度条加载
    画圆移动
    简单排序
    批量发货
    Angular服务
    终极购物车
  • 原文地址:https://www.cnblogs.com/BaseAI/p/11407233.html
Copyright © 2011-2022 走看看