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
#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的更多相关文章
- [hihocoder 1033]交错和 数位dp/记忆化搜索
#1033 : 交错和 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描写叙述 给定一个数 x,设它十进制展从高位到低位上的数位依次是 a0, a1, ..., an - 1 ...
- hihoCoder 1033 : 交错和 数位dp
思路:数位dp,dp(i, j, k)表示考虑i位数,每位数可以任意取[0~9],并且这i位数的交错和为j,k=1表示前缀全是0(如000456),k=0表示前缀不为0.注意,前缀是否为0是这道题的一 ...
- HihoCoder 1033交错和(数位DP第三题)
(写挂了,有空再补) 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个数 x,设它十进制展从高位到低位上的数位依次是 a0, a1, ..., an - 1,定义 ...
- 数位dp/记忆化搜索
一.引例 #1033 : 交错和 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个数 x,设它十进制展从高位到低位上的数位依次是 a0, a1, ..., an ...
- 【BZOJ1662】[Usaco2006 Nov]Round Numbers 圆环数 数位DP
[BZOJ1662][Usaco2006 Nov]Round Numbers 圆环数 Description 正如你所知,奶牛们没有手指以至于不能玩"石头剪刀布"来任意地决定例如谁 ...
- bzoj1026数位dp
基础的数位dp 但是ce了一发,(abs难道不是cmath里的吗?改成bits/stdc++.h就过了) #include <bits/stdc++.h> using namespace ...
- uva12063数位dp
辣鸡军训毁我青春!!! 因为在军训,导致很长时间都只能看书yy题目,而不能溜到机房鏼题 于是在猫大的帮助下我发现这道习题是数位dp 然后想起之前讲dp的时候一直在补作业所以没怎么写,然后就试了试 果然 ...
- HDU2089 不要62[数位DP]
不要62 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- 数位DP GYM 100827 E Hill Number
题目链接 题意:判断小于n的数字中,数位从高到低成上升再下降的趋势的数字的个数 分析:简单的数位DP,保存前一位的数字,注意临界点的处理,都是套路. #include <bits/stdc++. ...
随机推荐
- 两段锁协议(Two-Phase Locking――2PL)
两段锁协议(Two-Phase Locking――2PL) 两段锁协议规定所有的事务应遵守的规则: ① 在对任何数据进行读.写操作之前,首先要申请并获得对该数据的封锁. ② 在释放一个封锁之后,事务不 ...
- OAuth2基本概念和运作流程
OAuth(开放授权)是一个关于授权的开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用.目前的版本是2.0版,本文 ...
- UVA10817-Headmaster's Headache(动态规划基础)
Problem UVA10817-Headmaster's Headache Time Limit: 4500 mSec Problem Description Input The input con ...
- centos7修改系统语言为简体中文
centos7修改系统语言为简体中文 说明 自己装系统时一般都可以自定义选择系统语言.可是云端服务器一般都是安装好的镜像,默认系统语言为英文,对于初学者可能还会有搞不懂的计算机词汇.这里简单说一下ce ...
- AJAX方式发送远程请求报错:No 'Access-Control-Allow-Origin' header
AJAX GET方式发送远程请求,chrome开发者工具console中报错:XMLHttpRequest cannot load http://www.shikezhi.com/ajax/getDa ...
- Linux下简单的缓冲区溢出
缓冲区溢出是什么? 科班出身,或者学过汇编的应该知道,当缓冲区边界限制不严格时,由于变量传入畸形数据或程序运行错误,导致缓冲区被“撑爆”,从而覆盖了相邻内存区域的数据 成功修改内存数据,可造成进程劫持 ...
- docker 2 docker介绍
docker是基于go语言实现的云开源项目 docker的主要目标是‘build ,ship and run any app,anywhere’,也就是说通过对应用程序组件的封装,分发,部署,运行等生 ...
- with as 加上 materialize hint 生成实质临时表
WITH AS: 就是将一个子查询部分独立出来,有时候是为了提高SQL语句的可读性,有时候是为了提高SQL语句性能. 如果一个SQL语句中,某个表会被访问多次,而且每次访问的限制条件一样的话,就可以使 ...
- Tomcat的九个内置对象
在之前学习过程中使用的对象大部分都是我们自己使用new关键字或者反射创建的,现在容器中会自动创建对象,我们只要直接使用即可,不需要我们再去创建这些对象,在Tomcat容器中提供了九种内置对象,有一些不 ...
- java可重入锁reentrantlock
public class ReentrantDemo { //重入锁 保护临界区资源count,确保多线程对count操作的安全性 /*public static ReentrantLock rtlo ...