hihoCoder1033 交错和 数位DP

Posted hchlqlz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hihoCoder1033 交错和 数位DP相关的知识,希望对你有一定的参考价值。

题目:交错和

链接:http://hihocoder.com/problemset/problem/1033#

题意:对于一个十进制整数x,令a0、a1、a2、...、an是x从高位到低位的数位,定义f(x)=a0-a1+a2-a3+...an,给出L、R、K,x在L到R之间,求所有满足:f(x)=k的x的和。(0 ≤ l ≤ r ≤ 10^18, |k| ≤ 100)

思路:

  L与R太大,连预处理的可能性都没有,很明显的数位DP。

  令dp[i][j]为精确的(有前导0)i 位,f(x)值为j 的x的和

  令dd[i][j]为精确的i 位,f(x)值为j 的x的个数。

  dp[1][i] = i (i从0-9)

  dd[1][i] = 1(i从0-9)

  当i为奇数时,最后一位前的符号位+,所以dp[i][j] = dp[i][j] + dp[i-1][j-u]*10 + u*dd[i-1][j-u] (u从0-9)

  dd[i][j]=dd[i][j] + dd[i-1][j-u] (u从0-9)

  当i为偶数时,将j-u改成j+u即可

  注意这里的dp求的和是有前导0的,比如3位数里098的f值为0-9+8也就是-1,所以dp[3][k]并不是0到1000里f值为k的数的和,因此我们要重新计算一个不含前导0的。

  令op[i][j]为i 位,f(x)值为j 的x的和

  令pp[i][j]为i 位,f(x)值为j 的x的个数。

  递推方法与dp一样,不同的是初始化,特别的令pp[1][0]=0,这样,等会递推出来的就是不包含前导0的,之后,为了方便,我们可以重新定义op[i][j]为前i 位,f(x)值为j 的x的和,pp也一样,进行下前缀和计算就可以了。

  解决完以上两步,这个问题便简单很多了,l到r,我们可以先算出0-r的,再减去0-l的,因此问题就转化成x属于0-l,f(x)值为k的x的和了,比如说3256,那么我们可以先算1000里有多少,1000-2000有多少,2000-3000有多少,再算3000-3100里有多少,3100-3200里有多少......1000里的直接就是op[3][k],1000到2000的,我们可以遍历u从0-9,现在就是1-u+?-?=k有多少了,那么?-?的值应该是k-1+u,也就是op[2][k-1+u],同时注意下细节就可以了。具体看代码。

  注:值得注意的是dd[0][0]=1,pp[0][0]=1

  

  1 #include<stdio.h>
  2 #include<iostream>
  3 using namespace std;
  4 #define Mod 1000000007
  5 typedef long long LL;
  6 LL dp[20][300]={0};
  7 LL dd[20][300]={0};
  8 LL op[20][300]={0};
  9 LL pp[20][300]={0};
 10 int getPos(int val)
 11 {
 12   return val+100;
 13 }
 14 void Init()
 15 {
 16   dd[0][100]=1;
 17   for(int i=0;i<=9;i++) dd[1][getPos(i)]=1,dp[1][getPos(i)]=i;
 18   for(int i=2;i<=18;i++)
 19   {
 20     if(i&1)
 21     {
 22       for(int j=0;j<10;j++)
 23       {
 24         for(int k=j;k<=200;k++)
 25         {
 26           dp[i][k]=(dp[i][k]+dp[i-1][k-j]*10%Mod+j*dd[i-1][k-j]%Mod)%Mod;
 27           dd[i][k]=(dd[i][k]+dd[i-1][k-j])%Mod;
 28         }
 29       }
 30     }
 31     else
 32     {
 33       for(int j=0;j<10;j++)
 34       {
 35         for(int k=0;k<=200-j;k++)
 36         {
 37           dp[i][k]=(dp[i][k]+dp[i-1][k+j]*10%Mod+j*dd[i-1][k+j]%Mod)%Mod;
 38           dd[i][k]=(dd[i][k]+dd[i-1][k+j])%Mod;
 39         }
 40       }
 41     }
 42   }
 43 
 44   for(int i=0;i<=9;i++) pp[1][getPos(i)]=1,op[1][getPos(i)]=i;
 45   pp[1][getPos(0)]=0;
 46   for(int i=2;i<=18;i++)
 47   {
 48     if(i&1)
 49     {
 50       for(int j=0;j<10;j++)
 51       {
 52         for(int k=j;k<=200;k++)
 53         {
 54           op[i][k]=(op[i][k]+op[i-1][k-j]*10%Mod+j*pp[i-1][k-j]%Mod)%Mod;
 55           pp[i][k]=(pp[i][k]+pp[i-1][k-j])%Mod;
 56         }
 57       }
 58     }
 59     else
 60     {
 61       for(int j=0;j<10;j++)
 62       {
 63         for(int k=0;k<=200-j;k++)
 64         {
 65           op[i][k]=(op[i][k]+op[i-1][k+j]*10%Mod+j*pp[i-1][k+j]%Mod)%Mod;
 66           pp[i][k]=(pp[i][k]+pp[i-1][k+j])%Mod;
 67         }
 68       }
 69     }
 70   }
 71   pp[0][getPos(0)]=1;
 72   for(int i=1;i<=18;i++)
 73   {
 74     for(int j=0;j<=200;j++)
 75     {
 76       op[i][j]=(op[i][j]+op[i-1][j])%Mod;
 77       pp[i][j]=(pp[i][j]+pp[i-1][j])%Mod;
 78     }
 79   }
 80 }
 81 
 82 LL solve(LL x,LL p)
 83 {
 84   if(x<0) return 0;
 85   LL tmp=x;
 86   int bt[20],bo=0;
 87   while(x)
 88   {
 89     bt[bo++]=x%10;
 90     x/=10;
 91   }
 92   LL io=1;
 93   for(int i=1;i<bo;i++)
 94     io=io*10;
 95   LL sum=0,k=0,kk=0;
 96   for(int i=bo-1;i>0;i--)
 97   {
 98     if((bo-i)&1)
 99     {
100       for(int j=0;j<bt[i];j++)
101       {
102         if(i==bo-1&&j==0)
103         {
104           sum=(sum+op[i][getPos(p)])%Mod;
105         }
106         else
107         {
108           for(int u=0;u<=9;u++)
109           {
110             sum=(sum+(kk*100%Mod+j*10+u)%Mod*io/10%Mod*dd[i-1][getPos(p+u-j-k)]%Mod+dp[i-1][getPos(p+u-j-k)])%Mod;
111           }
112         }
113       }
114       k+=bt[i];
115       kk=(kk*10%Mod+bt[i])%Mod;
116     }
117     else
118     {
119       for(int j=0;j<bt[i];j++)
120       {
121         sum=(sum+(kk*10%Mod+j)%Mod*io%Mod*dd[i][getPos(p+j-k)]%Mod+dp[i][getPos(p+j-k)])%Mod;
122       }
123       k-=bt[i];
124       kk=(kk*10%Mod+bt[i])%Mod;
125     }
126     io/=10;
127   }
128   if(bo&1)
129   {
130     for(int i=0;i<=bt[0];i++)
131       if(p-k==i)
132       {
133         sum=(sum+kk*10%Mod+i)%Mod;
134       }
135   }
136   else
137   {
138     for(int i=0;i<=bt[0];i++)
139       if(k-p==i) sum=(sum+kk*10%Mod+i)%Mod;
140   }
141   return sum;
142 }
143 int main()
144 {
145   Init();
146   LL l,r,k;
147   cin>>l>>r>>k;
148   cout<<(solve(r,k)-solve(l-1,k)+Mod)%Mod<<endl;
149   return 0;
150 }
AC代码

 

  

以上是关于hihoCoder1033 交错和 数位DP的主要内容,如果未能解决你的问题,请参考以下文章

hihoCoder 1033: 交错和

交错和(数位dp)

HihoCoder1076 与链(数位DP)

如何有效地去交错位(逆莫顿)

hihocoder #1301 : 筑地市场 数位dp+二分

数位DP hihocoder1791