BNUOJ---29141 背包密码

来源:互联网 发布:手机如何申请淘宝直播 编辑:程序博客网 时间:2024/05/01 14:56

背包密码系统是一种非常经典的公钥密码系统,这种密码系统加密过程如下:

  1. 选取一个长度为n的正整数超递增序列a[i],满足a[1]<a[2],a[1]+a[2]<a[3],……,a[1]+a[2]+…+a[n-1]<a[n]。
  2. 选取正整数m>2*a[n],w和m互质,v是w模m的逆,即(v*w)%m=1。b[i]=(w*a[i])%m。
  3. 加密时,对一段长为n的二进制串x[i]。有S= (b[1]*x[1]+b[2]*x[2]+…+b[n]*x[n])%m。
现在告诉你b[i]、v和m以及S,请你帮忙进行解密。
http://www.bnuoj.com/bnuoj/problem_show.php?pid=29141
v是w的逆,所以可以求解出a[i] = (b[i] * v) % m.
因为sum = ∑a[i](i = 1~n-1) < a[n],所以当a[i] <= sum时,a[i] += ((sum - a[i]) + 1) * m, 使其大于sum。
S= (b[1]*x[1]+b[2]*x[2]+…+b[n]*x[n])%m
 =w *(a[1]*x[1]+a[2]*x[2]+…+a[n]*x[n]) % m
∑a[i] * x[i] = (S * v) % m,令ans = (S * v) % m
由于a[i]是超递增序列,当ans > a[i]时,x[i]一定为1。因为a[1] +.... + a[i - 1] < a[i] 。由此便可解出x[i].
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long ll;const int maxn = 35;ll t, n, b[maxn], v, m, s, a[maxn], x[maxn];int main(){    scanf("%lld", &t);    while(t--){        memset(x, 0, sizeof(x));        scanf("%lld", &n);        for(int i=0; i<n; i++) scanf("%lld", &b[i]);        scanf("%lld%lld%lld", &v, &m, &s);        ll sum = 0;        for(int i=0; i<n; i++){            a[i] = (b[i] * v) % m;            if(a[i] <= sum)                a[i] += m * ((sum - a[i]) / m + 1);        }        ll ans = (v * s) % m;        for(int i=n-1; i>=0; i--){            if(a[i] <= ans){                x[i] = 1;                ans -= a[i];            }        }        for(int i=0; i<n; i++) printf("%lld", x[i]);        puts("");    }    return 0;}


0 0
原创粉丝点击