模拟赛 某种密码()

题目描述

关于某种密码有如下描述:某种密码的原文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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值