• [20181015][模拟赛]


    题目

    关于某种密码有如下描述:某种密码的原文A是由N个数字组成,而密文B是一个长度为N的01数串,原文和密文的关联在于一个钥匙码KEY。若(KEY=sumlimits_{i=1}^n{[A_i*B_i]}),则密文就是原文的一组合法密码。

    现在有原文和钥匙码,请编一个程序来帮助他统计到底有多少个符合条件的密文。

    【输入数据】

    第一行两个数N,KEY,意义同题目描述;

    第二行N个数表示原文A,意义同题目描述。

    【输出数据】

    一个数ANS,表示对于原文A和KEY,有多少组可行的密文B。

    【输入样例】

    3 2

    1 1 2

    【输出样例】

    2

    【样例说明】

    密文110,11+11+0*2=2

    密文001,01+01+1*2=2

    一共两组可行的密文。

    【数据约定】

    60%数据满足$Nleqslant$25

    100%数据满足(Nleqslant40)(-maxlongintleqslantsumlimits_{i=1}^na[i]leqslant maxlongint)

    思路

    其实题目的意思就是说,给出一个数KEY,和一个长度为n的数组a,求出从a中找出任意多个数和为KEY的方案数。第一档分就是(2^n)搜索了,对于第二档分,一直没想出是什么算法,后来才知道有个叫做meet in the middle的算法。

    其实很简单,就是把搜索树的深度减小一半。先正着搜索,控制深度mid,搜到底部时,用一个map或者数组记录下搜到的数的次数。然后再从后面倒着搜,也是控制深度为mid,然后搜到底部时,把还需要的数的计数加上就可以了。

    代码

    #include <cstdio>
    #include <map>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    map <int , ll > ma;
    ll read() {
    	ll x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9') {
    		if(c=='-') f=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9') {
    		x=x*10+c-'0';
    		c=getchar();
    	}
    	return x*f;
    }
    int key ,n,mid;
    int a[50];
    void dfs1(int now,int k) {
    	if(now == mid + 1) {
    		ma[k]++;
    		return;
    	}
    	dfs1(now + 1,k - a[now]);
    	dfs1(now + 1,k);
    }
    ll dfs2(int now,int k) {
    	if(now == mid)
    		return ma[key - k];
    	ll ans = 0;
    	ans += dfs2(now - 1,k - a[now]);
    	ans += dfs2(now - 1, k);
    	return ans;
    }
    int main() {
    	n = read(),key = read();
    	mid = n>>1;
    	for(int i = 1;i <= n;++i)
    		a[i] = read();
    	dfs1(1,key);
    	cout<<dfs2(n,key);
    	return 0;
    }
    

    一言

    坐亦禅,行亦禅,一花一世界,一叶一如来,春来花自青,秋至叶飘零,无穷般若心自在,语默动静体自然。 ——佛教禅语

  • 相关阅读:
    Project项目视图
    Console(控制台视图)
    Layout布局列表
    Layers层列表
    帐户下拉
    TransformGizmo(变换)切换
    Play播放控件
    变换工具
    工具栏
    Help帮助
  • 原文地址:https://www.cnblogs.com/wxyww/p/9798730.html
Copyright © 2020-2023  润新知