zoukankan      html  css  js  c++  java
  • 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代码

     

      

  • 相关阅读:
    php解析文本文件呈现在表格上
    nyoj 1058部分和问题
    nyoj 488素数环
    nyoj 82迷宫寻宝(一)
    nyoj58最少步数
    nyoj 325 zb的生日
    nyoj 20 吝啬的国度
    nyoj 349 Sorting It All Out
    nyoj 284
    PPT基础整理
  • 原文地址:https://www.cnblogs.com/hchlqlz-oj-mrj/p/5589330.html
Copyright © 2011-2022 走看看