• 2014.10.4模拟赛【某种密码】


    某种密码(password.*)

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


    题意是给定n个数,要求做01背包之后和为key的方案数

    首先n<=25的直接2^n爆搜就好了

    当n<=40的时候,有一种做法是类似“方程的解数”那题的前后分开暴力

    假设b[]是一个满足Σa[i]*b[i]=key的01序列

    首先,b[]数组必须刚好n个数

    显然b[]数组最多有2^40种不同的排列,直接爆搜会T

    但是我们把b[]的前n/2个元素暴力枚举出来,最坏情况下是2^20,用hash存起来

    然后再暴力枚举后n-n/2个,最坏也是2^20,统计答案的时候只要找前面跟它刚好匹配的方案数就好了

    比如找到一种和为a的方案,只要在哈希表中找前20个中和为key-a的方案数累加就好了

    这样复杂度降到(n/2)*2^(n/2)

    在考场上a[i]开了long long但是读入没有用%lld就只有70……蛋疼

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define LL long long
    #define mod 1000007
    #define deliver n/2
    using namespace std;
    struct hashing{
    	LL next,rep;
    	LL v;
    }hash[5000000];
    int head[mod];
    int n,m,cnt;
    LL ans;
    LL a[100];
    inline void ins(LL u,LL w)
    {
    	hash[++cnt].v=w;
    	hash[cnt].rep=1;
    	hash[cnt].next=head[u];
    	head[u]=cnt;
    }
    inline void insert(LL u,LL w)
    {
    	LL s=w%mod;while(s<0)s+=mod;
    	for(int i=head[s];i;i=hash[i].next)
    	  if (hash[i].v==w)
    	  {
    	  	hash[i].rep++;
    	  	return;
    	  }
    	ins(s,w);
    }
    inline int get(int u)
    {
    	LL w=(LL)(m-u);
    	LL s=w%mod;while (s<0)s+=mod;
    	for (int i=head[s];i;i=hash[i].next)
    	  if (hash[i].v==w)return i;
    	return -1;
    }
    int main()
    {
    	freopen("password.in","r",stdin);
    	freopen("password.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++)scanf("%lld",&a[i]);
    	sort(a+1,a+n+1);
    	for(int i=0;i<=(1<<deliver)-1;i++)
    	  {
    	  	LL tot=0;
    	  	for (int j=1;j<=deliver;j++)
    	  	  if (i & (1<<(j-1)))tot+=a[j];
    	  	insert(tot,tot);
    	  }
    	for (int i=0;i<=(1<<(n-deliver))-1;i++)
    	{
    		LL tot=0;
    		for (int j=1;j<=n-deliver;j++)
    		  if (i & (1<<(j-1)))tot+=a[j+deliver];
    		int fnd=get(tot);
    		if (fnd!=-1)ans+=hash[fnd].rep;
    	}
    	printf("%lld
    ",ans);
    }
    

      

    ——by zhber,转载请注明来源
  • 相关阅读:
    Django 框架 # 51
    Django 框架 介绍# 51
    前端之Bootstrap框架 # 50
    phpcms调用一个指定的栏目的url和栏目名称
    phpcms导航栏调用二级栏目
    彻底弄懂JS的事件冒泡和事件捕获
    toggle 方法的使用
    关于内层DIV设置margin-top不起作用的解决方案
    phpmyadmin导入数据库大小限制修改
    phpcms v9 的表单向导功能的使用方法
  • 原文地址:https://www.cnblogs.com/zhber/p/4035891.html
Copyright © 2020-2023  润新知