Codeforces 525E Anya and Cubes

题意:给你n(25)个数,任选几个数 ,你最多可以对任选的几个数中的 K个数进行操作,操作是将 这个数变为它的阶乘,你选出来的数经过操作以后 等于 s的种类数有多少。

解题思路:看到这题的时候没什么思路,想想水一发dp  ,dp[i][j][k]<map>,就想到了这个四维的DP,但是显然这是会挂掉的。因为情况太多了,最多有 3^n种。

那么需要是什么方法呢。那就是折半了,因为我们只需要找到一个值, 而全部DP的话会产生太多的值了,而这大部分值都不是我们需要的。所以就把n个数分成两堆去处理,然后用中间值凑出s,这样复杂度就会少很多.

解题代码:

 1 // File Name: e.cpp
 2 // Author: darkdream
 3 // Created Time: 2015年03月27日 星期五 01时21分34秒
 4 
 5 #include<vector>
 6 #include<list>
 7 #include<map>
 8 #include<set>
 9 #include<deque>
10 #include<stack>
11 #include<bitset>
12 #include<algorithm>
13 #include<functional>
14 #include<numeric>
15 #include<utility>
16 #include<sstream>
17 #include<iostream>
18 #include<iomanip>
19 #include<cstdio>
20 #include<cmath>
21 #include<cstdlib>
22 #include<cstring>
23 #include<ctime>
24 #define LL long long
25 
26 using namespace std;
27 int n ,m ;
28 LL s ; 
29 LL a[100];
30 LL b[100];
31 map<int,map<LL,LL> > mpa;
32 map<int,map<LL,LL> > mpb;
33 map<LL,LL>::iterator tt;
34 int li;
35 void dfs(int p ,int k,LL v,map<int,map<LL,LL> > &tmp)
36 {
37     //printf("%d %d %I64d\n",p,k,v);
38     if(k > m)
39         return;
40     if(p == li + 1)
41     {
42       tmp[k][v] += 1 ;
43       return;
44     }
45     if(v + a[p] <= s)
46         dfs(p+1,k,v+a[p],tmp);
47     if(a[p] <= 18 && v + b[p] <= s)
48         dfs(p+1,k+1,v+b[p],tmp);
49     dfs(p+1,k,v,tmp);
50 }
51 int main(){
52     scanf("%d %d %I64d",&n,&m,&s);
53     for(int i = 1;i <= n;i ++)
54     {
55        scanf("%I64d",&a[i]);
56     }
57     sort(a+1,a+1+n);
58     for(int i = 1;i <= n;i ++)
59     {
60        if(a[i] <= 18)
61        {
62          b[i] = 1; 
63          for(int j = 1;j <= a[i]; j ++)
64          {
65            b[i] *= j;
66          }
67        }
68     }
69      li = n/2; 
70     dfs(1,0,0,mpa);
71     li = n; 
72     //puts("***");
73     dfs(n/2+1,0,0,mpb);
74     LL sum = 0 ; 
75     for(int i = 0 ;i <= m;i ++)
76     {
77         for(int j = 0 ;j + i <= m;j ++)
78         {
79            for(tt = mpa[i].begin(); tt != mpa[i].end();tt++)
80            {
81               sum += (mpb[j][s - tt->first]) * (tt->second);
82     //          printf("***%d %I64d %I64d %I64d\n",j,s-tt->first,mpb[j][s-tt->first],tt->second);
83            }
84         }
85     }
86     printf("%I64d\n",sum);
87     return 0;
88 }
View Code

 

转载于:https://www.cnblogs.com/zyue/p/4372922.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值