BZOJ 1026 windy数

     据说这是道数位dp的题,第一反应看到之后也觉得不难,大致思路马上就有了。(其实后来我所看的题解有一个和我想的也差不多,只不过好像觉得那样写太麻烦了,就不想写了,就开始和正道偏离了,所以有了思路之后一定要勇于尝试。)一开始是这样的,先处理出一个数组 f[i][j] 表示 第 i 位为 j 开头的符合题意的数有多少个。(经过这道题,也渐渐总结了一些经验,一开始思考不全面,没有处理好0的情况,所以以后一定要思考全面,把细节都想得差不多了再动手,否则后果真的……)。接下来,就因为0的问题,整个人乱掉了。后来就改成写搜索,然后TLE了(刚刚看了一下别人的题解,如果把爆搜改成记忆化搜索也是能过的,其实我也试着改了,以WA告终)。最后……。

       好吧,这是搜索的代码。其实和我写的差不多(我是指思路上,但是这份代码比我一开始写的简洁多了)。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #define rep(i,j,k) for(int i = j; i <= k; i++)
 5 using namespace std;
 6 int num[12] = {0}, dp[100][100] = {0};
 7 
 8 int abs(int x,int y)
 9 {
10     if( x > y )  return x - y; else return y - x;
11 }
12 int dfs(int po,int last,int ok,int first)
13 {
14     if( po == 0 ) return 1;
15     if( !first && ok ){
16         if( dp[po][last] != -1 ) return dp[po][last]; //记搜优化
17     }
18     int cur = first? num[po] : 9; // 这里写的很好。
19     int ans = 0;
20     if( ok ){
21         rep(i,0,cur){
22             if( abs(last,i) >= 2 ) ans += dfs(po-1,i,ok,first&&i==cur);  // 这里写的很好。
23         }
24     }
25     else {
26         rep(i,0,cur){
27             ans += dfs(po-1,i,i,first&&i==cur);
28         }
29     }
30     if( !first && ok ) {
31         return dp[po][last] = ans; // 记搜优化
32     }
33     return ans;
34 }
35 
36 int dpa(int n)
37 {
38     int tot = 0;
39     while( n ){
40         num[++tot] = n % 10;
41         n /= 10;
42     }
43     return dfs(tot,0,0,1);
44 }
45 
46 int main()
47 {
48     memset(dp,-1,sizeof(dp));
49     int n, m; scanf("%d %d",&n,&m);
50     cout<<dpa(m)-dpa(n-1)<<endl;
51     return 0;
52 }

 

    接下来是把 i 拆分出来后的代码!(也是我一开始的思路)。可以理解为把 i 划分成几个区间 设 i 最高位可以到 10 的 n 次方, 那么可以把 i 划分成 0 - 10的n次方-1,10的n次方-1到2*10的n次方-1。以此类推直到小于 i 的最高位上的数字。 对 i 的最高位 * 10 的 n 次方 到 i , 进行特殊处理。

 1 #include<cstdio>
 2 #include<iostream>
 3 #define rep(i,j,k) for(int i = j; i <= k; i++)
 4 #define down(i,j,k) for(int i = j; i >= k; i--)
 5 using namespace std;
 6 int f[11][10] = {0}, fabs[12] = {0};
 7 
 8 int abs(int x,int y)
 9 {
10     if( x > y ) return x - y; else return y - x;
11 }
12 
13 void init()
14 {
15     fabs[1] = 1;
16     rep(i,2,10){
17         fabs[i] = fabs[i-1] * 10;
18     }
19     rep(i,0,9) f[1][i] = 1;
20     rep(i,2,10){
21         rep(j,0,9){
22             rep(k,0,9){
23                 if( abs(j,k) >= 2 ){
24                     f[i][j] += f[i-1][k];
25                 }
26             }
27         }
28     }
29 }
30 
31 int work(int now)
32 {
33     if( !now ) return 0;
34     int tot = 10, ans = 0;
35     while( fabs[tot] > now ) tot--;
36     int cur = now / fabs[tot];
37     rep(i,1,cur-1)  ans += f[tot][i];
38     down(i,tot-1,1){
39             rep(j,1,9) ans += f[i][j];
40     }
41     now %= fabs[tot];
42     int pre = cur;
43     down(i,tot-1,1){
44         cur = now / fabs[i];
45         if( i == 1 ) cur++;
46         for(int j = 0; j <= 9 && j < cur; j++){
47             if( abs(pre,j) >= 2 ) ans += f[i][j];
48         }
49         pre = now / fabs[i];
50         now %= fabs[i];
51     }
52     return ans;
53 }
54 
55 int main()
56 {
57     init(); int n, m;
58     scanf("%d %d", &n, &m);
59     cout<<work(m)-work(n-1)<<endl;
60     return 0;
61 }
62     

都不难,加油!多想,勇于尝试。

 

1026: [SCOI2009]windy数

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 4518  Solved: 2020
[Submit][Status][Discuss]

Description

windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,在A和B之间,包括A和B,总共有多少个windy数?

Input

包含两个整数,A B。

Output

一个整数。

Sample Input

【输入样例一】
1 10
【输入样例二】
25 50

Sample Output

【输出样例一】
9
【输出样例二】
20

HINT

 

【数据规模和约定】

100%的数据,满足 1 <= A <= B <= 2000000000 。

 

Source

posted on 2015-12-24 19:37  83131  阅读(...)  评论(... 编辑 收藏

导航