zoukankan      html  css  js  c++  java
  • 数位dp--P2657 [SCOI2009] windy 数

    预处理:$f_{i,j}$表示填了$i$位数,最高位为$j$的windy数的个数,显然有$f_{i,j}$=$sum f_{i-1,k}$(|$j$-$k$|>=2)

    1 void init(){
    2   for (int i = 0;i <= 9;i++) dp[1][i]=1;
    3   for (int i = 2;i <= 10;i++)
    4     for (int j = 0;j <= 9;j++)
    5       for (int k = 0;k <= 9;k++)
    6     if (abs(j-k)>=2) dp[i][j]+=dp[i-1][k];
    7 }

    由于windy数的性质,可以利用前缀和,比如我要求[a,b]内windy数的个数,我们可以求出$0-b+1$和$0-a$内的windy数的个数再相减,可以把答案分成三个部分,求长度为$len$,$a$范围内的windy数的个数

    (1)先求$len-1$位的windy数的个数,必定包含在区间里

    1 for (int i = 1;i <= len-1;i++)
    2     for (int j = 1;j <= 9;j++) ans+=dp[i][j];

    (2)然后在看第$len$位,最高位<$a[len]$的windy数也一定包含在区间里

     1 for (int i = 1;i < a[len];i++) ans+=dp[len][i]; 

    (3)最后看最高位相等的情况,$i$从$len-1$枚举,规定$i$之前的数都已确定,即前缀相同,如果相差>=2就加入到答案中

    1  for (int i = len-1;i >= 1;i--){
    2     for (int j = 0;j <= a[i]-1;j++){
    3       if (abs(j-a[i+1])>=2) ans+=dp[i][j];
    4     }
    5     if (abs(a[i+1]-a[i])<2) break;
    6   }

    完整代码:

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <cstdio>
     4 #include <cstring>
     5 #define int long long
     6 using namespace std;
     7 int dp[15][15],a[20];
     8 void init(){
     9   for (int i = 0;i <= 9;i++) dp[1][i]=1;
    10   for (int i = 2;i <= 10;i++)
    11     for (int j = 0;j <= 9;j++)
    12       for (int k = 0;k <= 9;k++)
    13     if (abs(j-k)>=2) dp[i][j]+=dp[i-1][k];
    14 }
    15 int solve(int x){
    16   memset(a,0,sizeof(a));
    17   int len=0,ans=0;
    18   while (x){
    19     a[++len]=x%10;
    20     x/=10;
    21   }
    22   for (int i = 1;i <= len-1;i++)
    23     for (int j = 1;j <= 9;j++) ans+=dp[i][j];
    24   for (int i = 1;i < a[len];i++) ans+=dp[len][i];
    25   for (int i = len-1;i >= 1;i--){
    26     for (int j = 0;j <= a[i]-1;j++){
    27       if (abs(j-a[i+1])>=2) ans+=dp[i][j];
    28     }
    29     if (abs(a[i+1]-a[i])<2) break;
    30   }
    31   return ans;
    32 }
    33 int n,m;
    34 signed main(){
    35   scanf ("%lld%lld",&n,&m);
    36   init();
    37   cout<<solve(m+1)-solve(n)<<endl;
    38   return 0;
    39 }

     

  • 相关阅读:
    Java设计模式—模板方法模式
    STM32 常用GPIO操作函数记录
    GPIO 配置之ODR, BSRR, BRR 详解
    STM32F4先设置寄存器还是先使能时钟
    LDR指令的格式:
    printf函数重定向
    stm32F4各个库文件的作用分析
    STM32F4时钟设置分析
    STM32F407存储器和总线架构
    SPI移位寄存器
  • 原文地址:https://www.cnblogs.com/very-beginning/p/13786126.html
Copyright © 2011-2022 走看看