背包密码系统是一种非常经典的公钥密码系统,这种密码系统加密过程如下:
这种密码,告诉你b[i]就可以进行加密。但是仅有b[i]很难进行解密,因为需要求解一个普通的01背包问题 。只有再告诉你v和m,解密就会变得很简单,现在告诉你b[i]、v和m以及S,请你帮忙进行解密。
正整数T(T<100),代表数据组数。每组数据格式如下:
第一行正整数n(1<=n<=32)代表二进制串的长度
第二行n个正整数b[1]到b[n]
第三行三个整数,v和m以及S。
(保证所有输入都在10^9以内,提示:中间过程可能会用到long long)
对每组数据输出一行,解密得到的二进制串x[i]
2 3 3 6 1 4 11 4 4 1 18 20 24 2 33 5
1010110
思路:好题。
已知:
1.v*w%m=1
2.b[i]=(w*a[i])%m a[i]为递增数列
3.S= (b[1]*x[1]+b[2]*x[2]+…+b[n]*x[n]%m 求x[i]
解:
由2、3得:
4.S= ((w*a[1])%m*x[1]+(w*a[2])%m*x[2]+…+(w*a[n])%m*x[n])%m
4左右同乘以 v%m
S*v%m = v%m*((w*a[1])%m*x[1]+(w*a[2])%m*x[2]+…+(w*a[n])%m*x[n])%m
5.S*v%m =a[1]%m*x[1]+...+a[n]%m*x[n]
由1、2得:
b[i]*v%m=(w*a[i])%m*v%m
6.a[i]%m=b[i]*v%m
由5、6得:
S*v%m =b[1]*v%m*x[1]+...+b[i]*v%m*x[n]
x[i]为01所组成的编码
即时如 5=1*x[1]+2*x[2]+4*x[3](第一组样例推到来的) a[i]为递增数列 所以得优先从后往前考虑
如果s》=b[i]*v%m x[i]=1 s-=b[i]*v%m;
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define LL long long int main() { int t; scanf("%d",&t); while(t--) { LL n; scanf("%lld",&n); LL b[1005]; for(int i=0;i<n;i++) scanf("%lld",&b[i]); LL v,m,s; scanf("%lld%lld%lld",&v,&m,&s); for(int i=0;i<n;i++) { b[i]=b[i]*v%m; } s=s*v%m; // printf("s:%lld\n",s); // for(int i=0;i<n;i++) // printf("%lld ",b[i]); for(int i=0;i<n;i++) { if(s>=b[n-i-1]) { s-=b[n-i-1]; b[n-i-1]=1; } else b[n-i-1]=0; } for(int i=0;i<n;i++) printf("%lld",b[i]); printf("\n"); } }