题面:

WhatNext Software creates sequence generators that they hope will produce fairly random sequences of 16-bit unsigned integers in the range 0–65535. In general a sequence is specified by integers ABC, and S, where 1 ≤ A < 32768, 0 ≤ B < 65536, 2 ≤ C < 65536, and 0 ≤ S < CS is the first element (the seed) of the sequence, and each later element is generated from the previous element. If X is an element of the sequence, then the next element is

(A * X + B) % C

where '%' is the remainder or modulus operation. Although every element of the sequence will be a 16-bit unsigned integer less than 65536, the intermediate result A * X + B may be larger, so calculations should be done with a 32-bit int rather than a 16-bit short to ensure accurate results.

Some values of the parameters produce better sequences than others. The most embarrassing sequences to WhatNext Software are ones that never change one or more bits. A bit that never changes throughout the sequence is persistent. Ideally, a sequence will have no persistent bits. Your job is to test a sequence and determine which bits are persistent.

For example, a particularly bad choice is A = 2, B = 5, C = 18, and S = 3. It produces the sequence 3, (2*3+5)%18 = 11, (2*11+5)%18 = 9, (2*9+5)%18 = 5, (2*5+5)%18 = 15, (2*15+5)%18 = 17, then (2*17+5)%18 = 3 again, and we're back at the beginning. So the sequence repeats the the same six values over and over:

Decimal 16-Bit Binary
3 0000000000000011
11 0000000000001011
9 0000000000001001
5 0000000000000101
15 0000000000001111
17 0000000000010001
overall 00000000000????1

The last line of the table indicates which bit positions are always 0, always 1, or take on both values in the sequence. Note that 12 of the 16 bits are persistent. (Good random sequences will have no persistent bits, but the converse is not necessarily true. For example, the sequence defined by A = 1, B = 1, C = 64000, and S = 0 has no persistent bits, but it's also not random: it just counts from 0 to 63999 before repeating.)  Note that a sequence does not need to return to the seed: with A = 2, B = 0, C = 16, and S = 2, the sequence goes 2, 4, 8, 0, 0, 0, ....

Input

There are from one to sixteen datasets followed by a line containing only 0. Each dataset is a line containing decimal integer values for A, B, C, and S, separated by single blanks.

Output

There is one line of output for each data set, each containing 16 characters, either '1', '0', or '?' for each of the 16 bits in order, with the most significant bit first, with '1' indicating the corresponding bit is always 1, '0' meaning the corresponding bit is always 0, and '?' indicating the bit takes on values of both 0 and 1 in the sequence.

Sample Input

2 5 18 3
1 1 64000 0
2 0 16 2
256 85 32768 21845
1 4097 32776 248
0

Sample Output

00000000000????1
????????????????
000000000000???0
0101010101010101
0???000011111???

大意:

给定无符号整数 A , B , C 以及一个“种子数据”S ,每一次迭代令 S = ( A * S + B ) % C ,由于 2 ≤ C < 65536 ,所以S的值一定会周期出现。现将S化为16位二进制数,高位0补齐,在循环过程中S未变化的二进制位原样输出,变化的位输出问号。

题解:

16位二进制最大表示的数为十进制的65535,我们在判断S是否周期出现时,开一个大小为65536(索引0~65535)的bool数组就行,迭代过程中如果发现数字重复出现,就退出迭代,寻找没有变化的位。在这里我使用了更加节省空间和时间的STL容器bitset。

bitset<65536> occ;
/*
*一些操作
*/
while (!occ.test(s)) {
occ.set(s);
//对s进行迭代操作
}

bitset的test(s)成员函数作用是对第s位的状态(true , false)进行判断,set(s)函数把第s位设置成true。那么如何判断某一位是否发生了变化呢?

我们定义一个无符号整型变量cmp,将它的前16位全部置为1,要实现这个,只需 cmp = ( 1 << 16 ) - 1即可。1 << 16是二进制下1后接16个0,减去1就是16个1了,简单的二进制减法。

同时我们记录下迭代前的数pre,迭代后的数cur。如何判断它们的二进制位有没有发生变化?我们知道,发生变化无非就是0变成1,1变成0,因此我们只要按位异或,得到的结果中,发生变化的二进制位就是1,没发生变化的就是0 。例如某次变化前为3,变化后为11,即0011 -> 1011 (为叙述方便省略前导0),异或得到的结果就是1000,代表从右往左第4位发生了变化。

接下来,我们如何将这个变化的信息记录在cmp中呢?

我的想法是,变化的位置0,没变化的位置1,因此我对异或的结果取反,即 1111 1111 1111 0111 (在这里,我完整写出了结果)。将这个结果与cmp(二进制表示为 1111 1111 1111 1111 )按位与,就得到了 1111 1111 1111 0111 。变化的信息得以记录,好耶!

接下来,11变化为9,即 1011 -> 1001 ,异或,取反,得到 1111 1111 1111 1101 。将这个结果与现在的cmp按位与。现在的cmp是1111 1111 1111 0111,第四位的0代表在先前的迭代中第4位发生了变化。虽然在这一轮中第四位没有发生变化,但是先前有啊!我们要记录这个信息。按位与之后,只有都是1的位才会被置1,所以未变化的位不受影响,先前变化过,这轮没有变化的位也会被记录下来变化过。因为0和1或者0按位与,结果都是0 。现在得到了 cmp = 1111 1111 1111 0101 ,代表在先前的变化中第2、4位发生了变化。这样下去,一轮下来,cmp的值就是 1111 1111 1111 0001,参考题面。这是实现这一过程的代码。

cmp = (1 << 16) - 1;
while (!occ.test(s)) {
occ.set(s);
cur = s = (a * s + b) % c;
cmp = (~(pre ^ cur))&cmp;//记录下变化的信息。
pre = cur;
}

接下来就是输出了。判断一个位是否发生变化?只要用特定位是1,其余位都是0的数去和它按位与即可。如果结果是0,说明发生了变化,输出“?”。如果结果不为0,说明该位没有发生变化,此时我们随便抓出一个变化过程中的量(毕竟没变化嘛)做按位与,测试它的值,非0输出1,否则输出0,即可。

unsigned bit = 1 << 15;//1000 0000 0000 0000
rep(i, 1, 16) {
if (bit & cmp) {
cout << (bit & pre ? 1 : 0);
} else {
cout << '?';
}
bit >>= 1;//0100 0000 0000 0000
}
cout << endl;

下面就是完整的AC代码啦~

#include <iostream>
#include <cstdio>
#include <bitset>
#include <algorithm>
#define grp int T;cin>>T;while(T--)
#define elif else if
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rrep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll; int main() { unsigned pre;
unsigned cur;
unsigned cmp;
bitset<65536> occ;
unsigned a, b, c, s;
while (cin >> a) {
if (a == 0) break;
cin >> b >> c >> s;
pre = s;
cmp = (1 << 16) - 1;
occ.reset();
while (!occ.test(s) && cmp) {
occ.set(s);
cur = s = (a * s + b) % c;
cmp = (~(pre ^ cur))&cmp;
pre = cur;
}
unsigned bit = 1 << 15;
rep(i, 1, 16) {
if (bit & cmp) {
cout << (bit & pre ? 1 : 0);
} else {
cout << '?';
}
bit >>= 1;
}
cout << endl;
} return 0;
}

Persistent Bits - 题解【二进制】的更多相关文章

  1. POJ - 3652 Persistent Bits

    “模拟”类型,题型容易,使用bitset库对二进制逐位操作,初始化.十进制转二进制(unsigned int).位操作. POJ - 3652 Persistent Bits Time Limit:  ...

  2. POJ 3652 &amp; ZOJ 2934 &amp; HDU 2721 Persistent Bits(数学 元)

    主题链接: PKU:http://poj.org/problem?id=3652 ZJU:http://acm.zju.edu.cn/onlinejudge/showProblem.do? probl ...

  3. CodeForces 485C Bits[贪心 二进制]

    C. Bits time limit per test1 second memory limit per test256 megabytes inputstandard input outputsta ...

  4. 【HDOJ】2721 Persistent Bits

    题目有点长,但是题意说的很清楚.位操作. #include <stdio.h> ]; int main() { int a, b, c, s; int i, j, k, n, tmp, m ...

  5. 【BZOJ5294】[BJOI2018]二进制(线段树)

    [BZOJ5294][BJOI2018]二进制(线段树) 题面 BZOJ 洛谷 题解 二进制串在模\(3\)意义下,每一位代表的余数显然是\(121212\)这样子交替出现的. 其实换种方法看,就是\ ...

  6. Tyvj3308毒药解药题解

    题目大意 这些药都有可能在治愈某些病症的同一时候又使人患上某些别的病症--经过我天才的努力.最终弄清了每种药的详细性能,我会把每种药能治的病症和能使人患上的病症列一张清单给你们,然后你们要依据这张清单 ...

  7. LeetCode编程训练 - 位运算(Bit Manipulation)

    位运算基础 说到与(&).或(|).非(~).异或(^).位移等位运算,就得说到位运算的各种奇淫巧技,下面分运算符说明. 1. 与(&) 计算式 a&b,a.b各位中同为 1 ...

  8. C#版 - Leetcode 191. Number of 1 Bits-题解

    版权声明: 本文为博主Bravo Yeung(知乎UserName同名)的原创文章,欲转载请先私信获博主允许,转载时请附上网址 http://blog.csdn.net/lzuacm. C#版 - L ...

  9. 算法与数据结构基础 - 位运算(Bit Manipulation)

    位运算基础 说到与(&).或(|).非(~).异或(^).位移等位运算,就得说到位运算的各种奇淫巧技,下面分运算符说明. 1. 与(&) 计算式 a&b,a.b各位中同为 1 ...

随机推荐

  1. ElasticSearch7.3 学习之定制动态映射(dynamic mapping)

    1.dynamic mapping ElasticSearch中有一个非常重要的特性--动态映射,即索引文档前不需要创建索引.类型等信息,在索引的同时会自动完成索引.类型.映射的创建. 当ES在文档中 ...

  2. vue&uniapp环境搭建以及项目创建(webstorm)

    以下是针对webstorm用户上手uniapp框架的学习 vue环境搭建以及配置(脚手架搭建) 首先要明确三样东西 npm:node.js的包管理器 webpack:主要用途是通过CommonJS 的 ...

  3. ubuntu16.04启动ssh服务

    1 查看ssh服务是否开启 ps -e | grep ssh* 2如果没有则安装ssh apt-get install openssh-server openssh-client 3再看服务就有ssh ...

  4. idea在新窗口中打开

    IntelliJ IDEA 2018.1.4 x64版本同时打开多个窗口可以进行如下设置,找到file--Settings...,然后会弹出下面的窗口:然后注意红框里的勾选项,最后确定Apply,OK ...

  5. kafka 保证消息被消费和消息只消费一次

    1. 保证消息被消费 即使消息发送到了消息队列,消息也不会万无一失,还是会面临丢失的风险. 我们以 Kafka 为例,消息在Kafka 中是存储在本地磁盘上的, 为了减少消息存储对磁盘的随机 I/O, ...

  6. Spring的自动装配?

    在spring中,对象无需自己查找或创建与其关联的其他对象,由容器负责把需要相互协作的对象引用赋予各个对象,使用autowire来配置自动装载模式. 在Spring框架xml配置中共有5种自动装配: ...

  7. 2020/12/28为止好用的PC下载工具

    IDM:http://www.internetdownloadmanager.com/ NDM(免费):http://www.neatdownloadmanager.com/index.php/en/ ...

  8. 学习Cobbler(二)

    Server端: 第一步,启动Cobbler服务 第二步,进行Cobbler错误检查,执行cobbler check命令 第三步,进行配置同步,执行cobbler sync命令 第四步,复制相关启动文 ...

  9. C#编写一个控制台应用程序,输入三角形或者长方形边长,计算其周长和面积并输出

    编写一个控制台应用程序,输入三角形或者长方形边长,计算其周长和面积并输出. 代码: using System; using System.Collections.Generic; using Syst ...

  10. leetcode-剑指 Offer II 012. 左右两边子数组的和相等

    题目描述: 给你一个整数数组 nums ,请计算数组的 中心下标 . 数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和. 如果中心下标位于数组最左端,那么左侧数之和视为 ...