您的位置:首页 > 其它

预生成密码(洛谷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;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: