传送门

完全没看懂题解在讲什么

由于\(C=\sum x_i\times a_i\),我们可以把\(x_i\)给二进制分解,然后依次考虑每一位

\(f_{i,j}\)表示考虑到\(C\)的二进制第\(i\)位,且\(0\)\(i-1\)位都已经对上,进位为\(j\)的方案数,那么考虑所有\(x_i\)当前这一位,每一个\(a_i\)最多选一个,用一个类似背包的东西计算出\(g_j\)表示总共进位为\(j\)的方案数,转移就是\(f_{i+1,j}+=g_{2j+c_{i+1}}\),其中\(c_{i}\)表示\(c\)的二进制第\(i\)

时间复杂度\(O(能过)\)

//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int P=1e9+7;
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
    R int res=1;
    for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
    return res;
}
const int N=1e5+5;
char ss[N];int a[N],f[2][N],g[N],st[N],sum,s,n,T,t,top,bg,ed;
void biu(){
    bg=1,ed=strlen(ss+1),top=0;
    fp(i,bg,ed)ss[i]-='0';
    while(bg<=ed){
        R int ret=0,tmp;
        fp(i,bg,ed)tmp=ret*10+ss[i],ss[i]=tmp>>1,ret=tmp&1;
        st[++top]=ret;
        while(bg<=ed&&!ss[bg])++bg;
    }
    memset(f,0,sizeof(f));
    f[t=0][0]=1,sum=0;
    fp(i,1,n)sum+=a[i];
    fp(k,1,top){
        memset(f[t^1],0,(sum+1)<<2);
        fp(j,sum+1,sum<<1)f[t][j]=0;
        s=-233333;
        fd(j,sum,0)if(f[t][j]){s=j;break;}
        fp(i,1,n){
            fd(j,s,0)upd(f[t][j+a[i]],f[t][j]);
            s+=a[i];
        }
        fp(j,0,sum)f[t^1][j]=f[t][j<<1|st[k]];
        t^=1;
    }
    printf("%d\n",f[t][0]);
}
int main(){
//  freopen("testdata.in","r",stdin);
    for(scanf("%d",&T);T;--T){
        scanf("%d%s",&n,ss+1);
        fp(i,1,n)scanf("%d",&a[i]);
        sort(a+1,a+1+n);
        biu();
    }
    return 0;
}
01-23 11:35