题目:交错和

链接: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

  

 #include<stdio.h>
#include<iostream>
using namespace std;
#define Mod 1000000007
typedef long long LL;
LL dp[][]={};
LL dd[][]={};
LL op[][]={};
LL pp[][]={};
int getPos(int val)
{
return val+;
}
void Init()
{
dd[][]=;
for(int i=;i<=;i++) dd[][getPos(i)]=,dp[][getPos(i)]=i;
for(int i=;i<=;i++)
{
if(i&)
{
for(int j=;j<;j++)
{
for(int k=j;k<=;k++)
{
dp[i][k]=(dp[i][k]+dp[i-][k-j]*%Mod+j*dd[i-][k-j]%Mod)%Mod;
dd[i][k]=(dd[i][k]+dd[i-][k-j])%Mod;
}
}
}
else
{
for(int j=;j<;j++)
{
for(int k=;k<=-j;k++)
{
dp[i][k]=(dp[i][k]+dp[i-][k+j]*%Mod+j*dd[i-][k+j]%Mod)%Mod;
dd[i][k]=(dd[i][k]+dd[i-][k+j])%Mod;
}
}
}
} for(int i=;i<=;i++) pp[][getPos(i)]=,op[][getPos(i)]=i;
pp[][getPos()]=;
for(int i=;i<=;i++)
{
if(i&)
{
for(int j=;j<;j++)
{
for(int k=j;k<=;k++)
{
op[i][k]=(op[i][k]+op[i-][k-j]*%Mod+j*pp[i-][k-j]%Mod)%Mod;
pp[i][k]=(pp[i][k]+pp[i-][k-j])%Mod;
}
}
}
else
{
for(int j=;j<;j++)
{
for(int k=;k<=-j;k++)
{
op[i][k]=(op[i][k]+op[i-][k+j]*%Mod+j*pp[i-][k+j]%Mod)%Mod;
pp[i][k]=(pp[i][k]+pp[i-][k+j])%Mod;
}
}
}
}
pp[][getPos()]=;
for(int i=;i<=;i++)
{
for(int j=;j<=;j++)
{
op[i][j]=(op[i][j]+op[i-][j])%Mod;
pp[i][j]=(pp[i][j]+pp[i-][j])%Mod;
}
}
} LL solve(LL x,LL p)
{
if(x<) return ;
LL tmp=x;
int bt[],bo=;
while(x)
{
bt[bo++]=x%;
x/=;
}
LL io=;
for(int i=;i<bo;i++)
io=io*;
LL sum=,k=,kk=;
for(int i=bo-;i>;i--)
{
if((bo-i)&)
{
for(int j=;j<bt[i];j++)
{
if(i==bo-&&j==)
{
sum=(sum+op[i][getPos(p)])%Mod;
}
else
{
for(int u=;u<=;u++)
{
sum=(sum+(kk*%Mod+j*+u)%Mod*io/%Mod*dd[i-][getPos(p+u-j-k)]%Mod+dp[i-][getPos(p+u-j-k)])%Mod;
}
}
}
k+=bt[i];
kk=(kk*%Mod+bt[i])%Mod;
}
else
{
for(int j=;j<bt[i];j++)
{
sum=(sum+(kk*%Mod+j)%Mod*io%Mod*dd[i][getPos(p+j-k)]%Mod+dp[i][getPos(p+j-k)])%Mod;
}
k-=bt[i];
kk=(kk*%Mod+bt[i])%Mod;
}
io/=;
}
if(bo&)
{
for(int i=;i<=bt[];i++)
if(p-k==i)
{
sum=(sum+kk*%Mod+i)%Mod;
}
}
else
{
for(int i=;i<=bt[];i++)
if(k-p==i) sum=(sum+kk*%Mod+i)%Mod;
}
return sum;
}
int main()
{
Init();
LL l,r,k;
cin>>l>>r>>k;
cout<<(solve(r,k)-solve(l-,k)+Mod)%Mod<<endl;
return ;
}

AC代码

  

hihoCoder1033 交错和 数位DP的更多相关文章

  1. [hihocoder 1033]交错和 数位dp/记忆化搜索

    #1033 : 交错和 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描写叙述 给定一个数 x,设它十进制展从高位到低位上的数位依次是 a0, a1, ..., an - 1 ...

  2. hihoCoder 1033 : 交错和 数位dp

    思路:数位dp,dp(i, j, k)表示考虑i位数,每位数可以任意取[0~9],并且这i位数的交错和为j,k=1表示前缀全是0(如000456),k=0表示前缀不为0.注意,前缀是否为0是这道题的一 ...

  3. HihoCoder 1033交错和(数位DP第三题)

    (写挂了,有空再补) 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个数 x,设它十进制展从高位到低位上的数位依次是 a0, a1, ..., an - 1,定义 ...

  4. 数位dp/记忆化搜索

    一.引例 #1033 : 交错和 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个数 x,设它十进制展从高位到低位上的数位依次是 a0, a1, ..., an  ...

  5. 【BZOJ1662】[Usaco2006 Nov]Round Numbers 圆环数 数位DP

    [BZOJ1662][Usaco2006 Nov]Round Numbers 圆环数 Description 正如你所知,奶牛们没有手指以至于不能玩"石头剪刀布"来任意地决定例如谁 ...

  6. bzoj1026数位dp

    基础的数位dp 但是ce了一发,(abs难道不是cmath里的吗?改成bits/stdc++.h就过了) #include <bits/stdc++.h> using namespace ...

  7. uva12063数位dp

    辣鸡军训毁我青春!!! 因为在军训,导致很长时间都只能看书yy题目,而不能溜到机房鏼题 于是在猫大的帮助下我发现这道习题是数位dp 然后想起之前讲dp的时候一直在补作业所以没怎么写,然后就试了试 果然 ...

  8. HDU2089 不要62[数位DP]

    不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  9. 数位DP GYM 100827 E Hill Number

    题目链接 题意:判断小于n的数字中,数位从高到低成上升再下降的趋势的数字的个数 分析:简单的数位DP,保存前一位的数字,注意临界点的处理,都是套路. #include <bits/stdc++. ...

随机推荐

  1. 两段锁协议(Two-Phase Locking――2PL)

    两段锁协议(Two-Phase Locking――2PL) 两段锁协议规定所有的事务应遵守的规则: ① 在对任何数据进行读.写操作之前,首先要申请并获得对该数据的封锁. ② 在释放一个封锁之后,事务不 ...

  2. OAuth2基本概念和运作流程

    OAuth(开放授权)是一个关于授权的开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用.目前的版本是2.0版,本文 ...

  3. UVA10817-Headmaster's Headache(动态规划基础)

    Problem UVA10817-Headmaster's Headache Time Limit: 4500 mSec Problem Description Input The input con ...

  4. centos7修改系统语言为简体中文

    centos7修改系统语言为简体中文 说明 自己装系统时一般都可以自定义选择系统语言.可是云端服务器一般都是安装好的镜像,默认系统语言为英文,对于初学者可能还会有搞不懂的计算机词汇.这里简单说一下ce ...

  5. AJAX方式发送远程请求报错:No 'Access-Control-Allow-Origin' header

    AJAX GET方式发送远程请求,chrome开发者工具console中报错:XMLHttpRequest cannot load http://www.shikezhi.com/ajax/getDa ...

  6. Linux下简单的缓冲区溢出

    缓冲区溢出是什么? 科班出身,或者学过汇编的应该知道,当缓冲区边界限制不严格时,由于变量传入畸形数据或程序运行错误,导致缓冲区被“撑爆”,从而覆盖了相邻内存区域的数据 成功修改内存数据,可造成进程劫持 ...

  7. docker 2 docker介绍

    docker是基于go语言实现的云开源项目 docker的主要目标是‘build ,ship and run any app,anywhere’,也就是说通过对应用程序组件的封装,分发,部署,运行等生 ...

  8. with as 加上 materialize hint 生成实质临时表

    WITH AS: 就是将一个子查询部分独立出来,有时候是为了提高SQL语句的可读性,有时候是为了提高SQL语句性能. 如果一个SQL语句中,某个表会被访问多次,而且每次访问的限制条件一样的话,就可以使 ...

  9. Tomcat的九个内置对象

    在之前学习过程中使用的对象大部分都是我们自己使用new关键字或者反射创建的,现在容器中会自动创建对象,我们只要直接使用即可,不需要我们再去创建这些对象,在Tomcat容器中提供了九种内置对象,有一些不 ...

  10. java可重入锁reentrantlock

    public class ReentrantDemo { //重入锁 保护临界区资源count,确保多线程对count操作的安全性 /*public static ReentrantLock rtlo ...