题目描述
关于某种密码有如下描述:某种密码的原文A是由N个数字组成,而密文B是一个长度为N的01数串,原文和密文的关联在于一个钥匙码KEY。若KEY=∑▒〖Ai*Bi〗,则密文就是原文的一组合法密码。
现在有原文和钥匙码,请编一个程序来帮助他统计到底有多少个符合条件的密文。
【输入数据】
第一行两个数N,KEY,意义同题目描述;
第二行N个数表示原文A,意义同题目描述。
【输出数据】
一个数ANS,表示对于原文A和KEY,有多少组可行的密文B。
【输入样例】
3 2
1 1 2
【输出样例】
2
【样例说明】
密文110,1*1+1*1+0*2=2
密文001,0*1+0*1+1*2=2
一共两组可行的密文。
【数据约定】
60%数据满足N<=25
100%数据满足N<=40,-maxlongint<=∑▒Ai<=maxlongint题解
60分可以2^n暴搜。100分分两半暴搜即可。
考场上打的,很难看……
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define ll long long
#define mod 199997
#define inf 1<<30
using namespace std;
int n,m,a[50];
ll ans,b[200002],s[200002];
void dfs(int x,ll ct)
{
if(x>n)
{if(ct==m) ans++;
return;
}
dfs(x+1,ct+a[x]);
dfs(x+1,ct);
}
void hash(ll x)
{
int y=x%mod;
//printf("%d\n",y);
if(y<0) y+=mod;
while(b[y]!=inf&&b[y]!=x) y=(y+1)%mod;
if(b[y]==x) {s[y]++; return;}
else {b[y]=x; s[y]=1; return;}
}
void dfs2(int x,ll ct)
{
if(x>n)
{hash(ct); return;}
dfs2(x+1,ct+a[x]);
dfs2(x+1,ct);
}
void check(ll x)
{
int y=x%mod;
if(y<0) y+=mod;
while(b[y]!=inf&&b[y]!=x) y=(y+1)%mod;
if(b[y]==x) {ans+=s[y]; return;}
else return;
}
void find(int x,ll ct)
{
if(x>n/2)
{check(m-ct); return;}
find(x+1,ct+a[x]);
find(x+1,ct);
}
int main()
{
freopen("password.in","r",stdin);
freopen("password.out","w",stdout);
scanf("%d%d",&n,&m);
int i;
for(i=1;i<=n;i++) scanf("%d",&a[i]);
if(n<=25) {dfs(1,0); printf("%I64d\n",ans); return 0;}
else
{for(i=0;i<=200000;i++) b[i]=inf;
dfs2(n/2+1,0); //printf("%d %d\n%d %d\n",b[0],s[0],b[1],s[1]);
find(1,0);
printf("%I64d\n",ans);
}
return 0;
}