1026: [SCOI2009]windy数

2021-03-31 11:27

阅读:584

 

【数据规模和约定】

100%的数据,满足 1

 

windy数的大致意思是:像135,6913,13579,这样每两个相邻数字的差≥2

数位dp:

正面直接猜想,保存2000000000状态无疑是不可能的,必须采用更加巧妙的方法。

可以设dp数组为:f[i][j],i表示数字位数,j表示最高位的数字

因此可以得到dp方程:

 

\[f[i][j]=\sum_{k=0}^{k\leq 9} f[i-1][k]\left (\left | k-j \right |\geq 2\right )\]

但这只计算出最高位为j的结果,无法求出范围内的结果,这时可以转换思想,求出1~b的结果减去1~a-1的结果,不就是答案了吗?

设len表示数字位数,T[i]表示第i位的数字

首先,ans加上1~len-1位的情况

然后ans加上最高位数字为1~T[len]-1的情况

接着以此类推,加上次最高位1~T[len-1]-1的情况,加上次次最高位1~T[len-2]-1的情况。。。。。。

 

 1 #include 2 #include 3 #include 4 #include 5 using namespace std;
 6 
 7 #define LL long long
 8 
 9 int a,b;
10 LL f[20][10];
11 
12 LL solve(int t)
13 {
14     LL ans=0;
15     int len=0,T[20];
16     while(t)
17     {
18         T[++len]=t%10;
19         t/=10;
20     }
21     for(int i=1;i)
22         for(int j=1;j9;j++)
23             ans+=f[i][j];
24     for(int i=1;i)
25         ans+=f[len][i];
26     for(int i=len-1;i>=1;i--)
27     {
28         for(int j=0;j)
29             if(abs(j-T[i+1])>=2)
30                 ans+=f[i][j];
31         if(abs(T[i]-T[i+1])2) break;
32     }
33     return ans;
34 }
35 
36 int main()
37 {
38     scanf("%d %d",&a,&b);
39     for(int i=0;i9;i++) f[1][i]=1;
40     for(int i=2;i15;i++)
41         for(int j=0;j9;j++)
42             for(int k=0;k9;k++)
43                 if(abs(k-j)>=2)
44                     f[i][j]+=f[i-1][k];
45     cout1)-solve(a)endl;
46     return 0;
47 }

 


评论


亲,登录后才可以留言!