预生成密码(洛谷9月月赛)
2017-09-18 19:16
274 查看
题目描述
众所周知,在一些特殊的部门,如果密码能够让一个人就解开,就会非常不安全。PIC(Pre-Invoked Code,预生成密码)诞生了。这个密码比较安全,是因为它必须由三个人保管。系统首先预先生成三个大整数a、b、c,计算出它们的与AND/或OR/和SUM并保存,然后将a、b、c分别告诉这三个人。需要使用密码解锁的时候,三个人必须依次输入这三个大整数才能成功。
那么为什么要计算这个与/或/和呢?这是PIC的“自救”功能:如果知道密码的三个人之中有人因为一些特殊的原因无法输入密码了,那么可以通过查阅该PIC的与/或/和的数值(这三个数值被其他的方式保护着,可以认为相当安全),并且根据手上的密码和这三个数值重新计算出剩下那个人的密码。
你是一位安全经理。你毫不费力的拿到一个PIC的与/或/和信息。你现在希望通过这个信息复原出原始代码。你当然清楚,满足这样限制的a、b、c是不唯一的,因此你希望最小(a尽可能小,a相同则b尽可能小,b相同则c尽可能小)的那一组开始尝试。
输入输出格式
输入格式:输入包含多组数据,以EOF结尾。
对于每一组数据,输入仅包含一行:AND,OR,SUM。
输出格式:
对于每一组数据输出一行:a、b、c,即为最小的那一组可能密码。
输入输出样例
输入样例#1:16 31 72 8 30 52
输出样例#1:
16 25 31 8 14 30
说明
记n为max(a,b,c),t为单点数据组数。对于10%的数据,n≤50;
对于30%的数据,n≤1000;
对于另外10%的数据,保证a=0;
对于另外10%的数据,保证a=b=c;
对于100%的数据,n≤10^18,t≤10。
[b]模拟水题[/b]
[b]首先复杂度必定为O(logn)[/b]
[b]我们把AND二进制分解,某一位为1代表a,b,c这一位都是1,确定一位,SUM-=3×(1<<i)[/b]
[b]把Or二进制分解,某一位为1代表a,b,c这一位至少有一个1,为0代表这一位没有1,我们贪心的全给c,不考虑a,b。SUM-=(1<<i)[/b]
[b]最后把剩下的SUM先尽可能分给b,在把剩下的给a[/b]
[b]代码中或搞错了,写成了Xor[/b]
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long lol; lol A,O,S,pw[101]; int And[1001],Xor[1001],a[1001],b[1001],c[1001]; void DvideA(lol x) {int i; for (i=60;i>=0;i--) {lol p=pw[i]; if (x>=p) { And[i]=1; x-=p; } } for (i=60;i>=0;i--) if (And[i]) {lol p=pw[i]; a[i]=1; b[i]=1; c[i]=1; S-=3*p; } } void DvideO(lol x) { int i; for (i=60;i>=0;i--) {lol p=pw[i]; if (x>=p) { Xor[i]=1; x-=p; } } for (i=60;i>=0;i--) if (c[i]==0&&Xor[i]) {lol p=pw[i]; c[i]=1; S-=p; } } void DvideS(lol x) {int i; for (i=60;i>=0;i--) {lol p=pw[i]; if (Xor[i]&&b[i]==0&&x>=p) { x-=p; b[i]=1; } } if (x) { for (i=60;i>=0;i--) { lol p=pw[i]; if (Xor[i]&&a[i]==0&&x>=p) { x-=p; a[i]=1; } } } } void printA() {int i; lol x=0; for (i=60;i>=0;i--) if (a[i]) x+=pw[i]; cout<<x<<' '; } void printB() {int i; lol x=0; for (i=60;i>=0;i--) if (b[i]) x+=pw[i]; cout<<x<<' '; } void printC() {int i; lol x=0; for (i=60;i>=0;i--) if (c[i]) x+=pw[i]; cout<<x<<' '; } int main() {int i; pw[0]=1; for (i=1;i<=60;i++) pw[i]=pw[i-1]*2; while (cin>>A>>O>>S) { memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(c,0,sizeof(c)); memset(And,0,sizeof(And)); memset(Xor,0,sizeof(Xor)); DvideA(A); DvideO(O); DvideS(S); printA(); printB(); printC(); cout<<endl; } }
相关文章推荐
- 洛谷9月月赛--T2[T2]预生成密码
- 洛谷9月月赛 康娜的线段树
- 揭开ASP.NET生成随机密码的面纱
- 洛谷 P3366 【模板】最小生成树
- [洛谷P4234] 最小差值生成树
- 批量生成卡号密码的php程序
- 利用 Linux 系统生成随机密码的10种方法 推荐
- mysql 随机生成密码
- 用python写的一个使用关键字定向生成密码字典的脚本
- shell 生成public key,实现免密码SSH登录
- 最小生成树+LCA【洛谷 P2245】 星际导航
- 密码字典生成【c语言】
- 密码生成常见的编码规则
- SQL Server 数据库帐号密码生成
- SQL Server 数据库帐号密码生成
- Python生成密码库功能示例
- mysql下用户和密码生成管理
- 使用Druid生成加密密码,实现mysql数据库连接用户密码加密解密
- C++全密码生成的实现代码
- thinkphp 表单提交生成数据库 用户 密码 赋权限 更改密码