码迷,mamicode.com
首页 > 其他好文 > 详细

[20181015][模拟赛]

时间:2018-10-16 17:35:00      阅读:125      评论:0      收藏:0      [点我收藏+]

标签:条件   统计   还需   span   数据   计数   namespace   是什么   for   

题目

关于某种密码有如下描述:某种密码的原文A是由N个数字组成,而密文B是一个长度为N的01数串,原文和密文的关联在于一个钥匙码KEY。若\(KEY=\sum\limits_{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%数据满足$N\leqslant\(25 ###100%数据满足\)N\leqslant40\(,\)-maxlongint<=\sum\limits_{i=1}^na[i]<=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;
}

[20181015][模拟赛]

标签:条件   统计   还需   span   数据   计数   namespace   是什么   for   

原文地址:https://www.cnblogs.com/wxyww/p/9798730.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!