SGU 258 Almost Lucky Numbers 接近幸运数(数位DP)

 

 

题意:

  定义一个具有2n位的正整数,其前n位之和与后n位之和相等,则为lucky数。给定一个区间,问有多少个正数可以通过修改某一位数从而变成lucky数?注意不能含前导0。

 

 

 

思路:

  我的想法是记录那些非lucky数,再想办法来统计,后来发现有点行不通,无法知道其前后部之和是否相等。如果记录lucky数,然后通过统计每个位上的数来变成lucky数,这更麻烦,因为会重复统计,比如11和22是lucky数,而21可以通过修改1位来变成lucky数,被统计了两次。

  学习了前辈的方法,也强迫一下自己别人的模板。据我对此模板的理解,第一次求解时是直接求解的,但是把所有统计过的都记录起来了,下次若还用到就直接返回就行了。复杂度是108吧。

 

 

  这是前辈们的代码,拿来理解一下,顺便适应一下新模板。

 1 #include <bits/stdc++.h>
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <cmath>
 6 #include <map>
 7 #include <algorithm>
 8 #include <vector>
 9 #include <iostream>
10 #define pii pair<int,int>
11 #define INF 0x7f3f3f3f
12 #define LL long long
13 #define ULL unsigned long long
14 using namespace std;
15 const double PI  = acos(-1.0);
16 const int N=10;
17 const int M=45;
18 const int mod=1e9+7;
19 
20 int f[N][N][99][N][N], bit[N+2];
21 
22 int dfs(int i,int up,int sum,int more,int less,bool e)    //e表示:是前缀?
23 {
24     if(i==0)
25         return (sum!=M && ( sum+more>=M && sum-less<=M ) );
26 
27     if(!e && ~f[i][up][sum][more][less])   //已经计算好了(非前缀才行)
28         return f[i][up][sum][more][less];
29 
30     int ans=0;
31     int d= i==up? 1: 0;        //起始,注意首位不能为0啊
32     int u= e? bit[i]: 9;       //终止,注意末位不能超啊
33     for( ; d<=u; d++)          //是否为最后一个取决于参数e
34     {
35         int ssum=  i>(up>>1)? sum+d: sum-d; //单峰形的
36         int mmore= i>(up>>1)? max(more, 9-d): max(more, d);   //前部:可加。后部:可减
37         int lless= i>(up>>1)? max(less, i==up?d-1:d): max(less, 9-d);//前部:可减。后部:可加
38         ans+=dfs(i-1,up, ssum, mmore, lless, e&&d==u);
39     }
40     return e? ans: f[i][up][sum][more][less]=ans; //前缀的返回不同
41 }
42 
43 
44 int cal(int n)
45 {
46     if(n<10)    return 0;   //仅个位数不可能是lucky数
47     int len=0, ans=0;
48     while(n)    //拆数
49     {
50         bit[++len]=n%10;
51         n/=10;
52     }
53 
54     for(int i=2; i<=len; i+=2)      //i是数的长度
55         ans+=dfs(i,i,0+M,0,0,i==len);
56     return ans;
57 }
58 
59 int main()
60 {
61     //freopen("input.txt","r",stdin);
62     memset(f,-1,sizeof(f));
63     int L, R;
64     while( ~scanf("%d%d",&L,&R) )
65         printf("%d\n", cal(R)-cal(L-1) );
66     return 0;
67 }
AC代码

 

posted @ 2015-10-03 22:43  xcw0754  阅读(414)  评论(0编辑  收藏  举报