P6962 [NEERC2017]Knapsack Cryptosystem
题意
给
Case 1
显然这一个超大背包问题,那么我们学过一个经典的折半的解决方法,复杂度
简单讲一下,就是暴力枚举前一半的所有选择方案,用一个数据结构把所有
inline void Solve(){
int mid = n>>1, tp = 1<<mid;
for(register int s=0; s<tp; s++){
ull sum=0;
for(register int i=1; i<=mid; i++) if((s>>i-1)&1) sum += b[i];
insert(sum,s);
}
tp = 1<<(n-mid);
for(register int s=0; s<tp; s++){
ull sum=0;
for(register int i=1; i<=n-mid; i++) if((s>>i-1)&1) sum += b[mid+i];
int ps = find(S-sum);
if(ps!=-1){
for(register int i=1; i<=mid; i++) if((ps>>i-1)&1) putchar('1'); else putchar('0');
for(register int i=1; i<=n-mid; i++) if((s>>i-1)&1) putchar('1'); else putchar('0');
puts("");
return;
}
}
}
Case 2
考虑
注意一下
for(register int i=n; i; i--)
if(S>=a[i]) S -= a[i], ans[i] = '1';
else ans[i] = '0';
首先根据性质2,是不用考虑取模的。其次,从大到小考虑时,如果
那么核心问题转为了如何求
根据性质1可以推出
于是想到枚举
ull tp=1ull<<(64-n-cnt-1);
for(register ull i=0; i<tp; i++){
ull a1 = (((i<<1)|1)<<cnt);
ull r = (a1>>cnt)*ksm(tmp,(1ull<<(64-cnt-1))-1);
if(cnt) r = r&((1ull<<64-cnt)-1);
}
但是这样求出的是模
ull tp1=1ull<<cnt;
for(register ull j=0; j<tp1; j++){
ull true_r = r|(j<<63-cnt+1);
check(true_r);
}
杂项
代码
出密码学的都是毒瘤
快速幂部分可以直接使用自然溢出快速幂,因为
关于复杂度,设两个