P4932 浏览器

P4932 浏览器

题目背景
__stdcall在用Edge玩slay的时候,鼠标会经常失灵,这让她十分痛苦,因此她决定也要让你们感受一下Edge制造的痛苦。

题目描述
__stdcall给了你n个点,第i个点有权值x[i],对于两个点u和v,如果x[u] xor x[v]的结果在二进制表示下有奇数个1,那么在u和v之间连接一个Edge,现在__stdcall想让你求出一共有多少个Edge。

如果你没能成功完成任务,那么__stdcall会让你痛苦一下,你这个测试点就没分了。

STL bitset

bitset 是 STL中性能优良的二进制载体, 优点在之前某篇博客说过了这里不再赘述
我只是想说 bitset快 !!! 牛逼 !!
这里说说 bitset 的赋值
实验发现 \(unsigned\ long\) 类型的数赋值给 \(bitset\) 要比 \(int\) 类型快, 防止出错以后都用 \(unsigned\ long\)

unsigned long x;
bitset<32>a(x);//初始赋值
int main(){
    a = x;//直接赋值
    }

Solution

失态失态
由于自带状态压缩, bitset 无论在执行位运算还是运行其中的函数都展现出很高的效率, 很厉害

打表找规律无解(from __stdcall)

我们记popcnt(x)表示x在二进制表示下1的个数。

观察之后不难发现,popcnt(a xor b)的奇偶性和popcnt(a)与popcnt(b)的奇偶性有关系。

具体来说,当popcnt(a)和popcnt(b)是一奇一偶的时候,popcnt(a xor b)是奇数,否则就是偶数。

因此,我们只需要统计每个点的权值的popcnt,用奇数的个数乘以偶数的个数就是答案。

然而 \(O(nlogv)\) 并不能过掉本题, 所以采用 \(count[bitset]\)

最后注意, bitset 函数运算速度与其大小成正比

Code

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<climits>
#include<bitset>
#define LL long long
#define REP(i, x, y) for(LL i = (x);i <= (y);i++)
using namespace std;
LL RD(){
    LL out = 0,flag = 1;char c = getchar();
    while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
    while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
    return flag * out;
    }
LL odd, eve;
LL n, a, b, c, d, x0;
bitset<32>x;
void work(LL n){
    REP(i, 1, n){
        x0 = (((a * x0 % d * x0 % d) + (b * x0 % d) + c) % d + d) % d;
        x = x0;
        LL cnt = x.count();
        if(cnt & 1)++odd;
        else ++eve;
        }
    printf("%lld\n", odd * eve);
    }
int main(){
    n = RD(), a = RD(), b = RD(), c = RD(), d = RD(), x0 = RD();
    work(n);
    return 0;
    }
posted @ 2018-10-21 21:15  Tony_Double_Sky  阅读(186)  评论(0编辑  收藏  举报