HDU 2089 不要62

DESC: 问l, r范围内的没有4和相邻62的数有多少个。

 #include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std; int dp[][]; /*
3种状态:
0:前i位不含有不吉利数字 的数 的个数
1:前i位不含有不吉利数字且第i+1位数字是6 的数 的个数
2:前i位含有不吉利数字 的数 的个数
*/ //int dfs(int i, int s, bool e) {
// if (i==-1) return s==target_s;
// if (!e && ~dp[i][s]) return dp[i][s];
// int res = 0;
// int u = e?num[i]:9;
// for (int d = first?1:0; d <= u; ++d)
// res += dfs(i-1, new_s(s, d), e&&d==u);
// return e?res:f[i][s]=res;
//} int num[];
int len; int dfs(int pos, int s, bool e) {
if (pos == ) return s != ; //遍历完之后 判断当前数字是否是不吉利数
if (!e && dp[pos][s]) return dp[pos][s];
int sum = ;
int maxm = e?num[pos]:; for (int d = ; d <= maxm; ++d) {
if (s == ) {
if (d == ) sum += dfs(pos-, , e&&(maxm == d));
else if (d == ) sum += dfs(pos-, , e&&(maxm == d));
else sum += dfs(pos-, , e&&(maxm == d));
}
else if (s == ) {
if (d == || d == ) sum += dfs(pos-, , e&&(maxm == d));
else if (d == ) sum += dfs(pos-, , e&&(maxm == d));
else sum += dfs(pos-, , e&&(maxm == d));
}
else if (s == ) sum += dfs(pos-, , e&&(maxm == d));
}
return e?sum:dp[pos][s]=sum;
} int solve(int x) {
len = ;
while(x) {
num[len++] = x%;
x /= ;
}
len -= ;
return dfs(len, , );
} int main() {
int n, m;
// cout << solve(100) << endl;
memset(dp, , sizeof(dp));
while(~scanf("%d%d", &n, &m)) {
if (n == && m == ) break;
int l = solve(n-);
int r = solve(m);
int ans = r - l;
printf("%d\n", ans);
}
return ;
}

CF 55D Beautiful numbers 数位DP+离散化

DESC:如果一个数能整除它每一位上的数字,那么这个数叫做美丽数。问 l, r范围内的美丽数有多少个。

状态:dp[20][2600][55]; // dp[i][j][k] = x表示前i位mod2520的值为j 且最小公倍数是lcms[k] 的美丽数有多少个。

lcms[]是1~9的所有可能产生的最小公倍数的映射数组。

因为1~9能产生的最大公倍数是2520,又x%y==0 等价于x%y%z == 0在z是y的因子时成立。所以我们只需要维护前i个数mod2520的值,就可以知道前i个数mod1~9的值。

即第二维压缩到2520。

判断当前数字是否是beautiful number等价于判断当前数是否mod (前i位的最小公倍数==0)。

所以我们需要维护前i位的最小公倍数。

而1~9能产生的最小公倍数位最大值位2520,小于55个。所以可以离散化,即第三维压缩到55。

开始设计的状态是:dp[20][2]表示前i位是或不是beautiful number。中间用一个num数组标记当前值mod(1~9)的值,最后判断是否是beautiful number。

但是这样前i位的值就受后面的值的影响,不能记忆化了。遂超时。

 #include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#define LL long long
using namespace std; const int maxn = ; LL dp[][][]; // dp[i][j][k] = x表示前i位mod2520的值为j 且最小公倍数是lcms[k] 的美丽数有多少个。
int num[];
int lcms[]; int gcd(int a, int b) {
return (b>?gcd(b, a%b):a);
} int ggcd(int a, int b) {
if (a == ) return b;
else if (b == ) return a;
return (a*b)/gcd(a, b);
} void getLcms() { //初始化lcms[]
memset(lcms, -, sizeof(lcms));
int num = ;
for (int i=; i*i<=maxn; ++i) {
if (maxn%i== && lcms[i] == -) { //能整除i
lcms[i] = num++;
int temp = maxn / i;
if (lcms[temp] == -)
lcms[temp] = num++;
}
}
} LL dfs(int pos, int pre, int lcm, bool lim) { // 当前位 前面i位mod2520的值 前面i-1位的lcm 当前位是否到最后一个数
if (pos == -) return (pre%lcm==); // 搜索到最后一位
if (!lim && dp[pos][pre][lcms[lcm]] != -) return dp[pos][pre][lcms[lcm]]; // 记忆化搜索
int mnum = (lim==?:num[pos]);
LL sum = ;
for (int i=; i<=mnum; ++i) {
int npre = (pre * + i) % maxn;
int nlcm = ggcd(lcm, i);
sum += dfs(pos-, npre, nlcm, lim&&(i==mnum));
}
return (lim==?dp[pos][pre][lcms[lcm]]=sum:sum);
} LL solve(LL x) {
int len = ;
while(x) {
num[len++] = x % ;
x /= ;
}
return dfs(len-, , , ); //
} int main() {
// freopen("in.cpp", "r", stdin);
memset(dp, -, sizeof(dp));
getLcms();
int t;
scanf("%d", &t);
while(t--) {
LL l, r;
scanf("%I64d%I64d", &l, &r);
LL ans = solve(r) - solve(l-);
printf("%I64d\n", ans);
}
return ;
}

附上大腿的代码,虽然加了两个z和zz数组这两个智障产物,有碍观瞻。但是,被有爱的注释感动了。有木有。

 #include <iostream>
#include <cstring>
#include <cstdio>
#include <map>
#define LL long long
using namespace std; /*首先,个位数最大的公倍数是5*7*8*9=2520 ,所以,我们第二维通过取余可以压缩到2520;打表可知,0-9组成的不同的公倍数不超过55个,所以第三压缩至55*/
long long state[][][];/*state[a][b][c] a:第几位 b:前a位数字代表的数对2520取余的值 c:前a位数字的公倍数,在id数组中的映射的值 */
int num[];/*都懂*/
int id[];/*所有可能出现的公倍数的映射,比如,9是可能出现的公倍数,就让id[9]=1;依次类推*/
int z[][];/*z[a][b] 存储的是 a与b的公倍数的值,在程序中,a指第i位的取值,b指前i-1位的公倍数,即dfs中传入的变量lcm*/
int zz[][];/*zz[a][b] 存储的是 前i-1位为b 新一位为 a 得到的新的数为多少,这个和上面那个其实没什么用,只是当时没找到正确超时的点,所以加上的*/
int _index=,num2=;/*num2为上面id那个数组的计数*/ long long gcd(long long a,long long b)
{
return (b>?gcd(b,a%b):a);
}/*求公倍数*/ void init()/*初始化*/
{
for(int i=;i*i<=;i++)
{
if(%i==)
{
id[i]=num2++;
if(i*i!=)id[/i]=num2++;
}
}/*初始化id,原理是,2520必定是其他可能公倍数的倍数,因为2520=9*8*7*5,1,2,3,4,6,都是5 7 8 9的因数*/
for(int i=;i<=;i++)
{
for(int j=;j<=;j++)
{
z[i][j]=(i==?j:j*i/gcd(j,i));
}
for(int j=;j<=;j++)
{
zz[i][j]=(j*+i)%;
}
}/*z zz数组初始化*/
// cout<<1<<endl;
} void getnum(long long x)
{
memset(num,,sizeof(num));
_index=;
while(x>)
{
num[_index++]=x%;
x=x/;
}
// cout<<num[0]<<endl;
} long long dfs(int i,long long st,long long lcm,int limit)/*st 前i位代表的数 lcm 前i位数的公倍数*/
{
if(i==-)return st%lcm==;
if(!limit&&state[i][st][id[lcm]]!=-)return state[i][st][id[lcm]];
int maxn=limit?num[i]:;
//cout<<lcm<<endl;
long long ans=;
for(int j=;j<=maxn;j++)
{
ans+=dfs(i-,i?zz[j][st]:st*+j,z[j][lcm],limit&&j==maxn);
}
return limit?ans:state[i][st][id[lcm]]=ans;
} long long solve(long long x)
{
getnum(x);
return dfs(_index-,,,);
} int main()
{
freopen("codeforces55D.in.cpp","r",stdin);
int t;
long long l,r;
init();
memset(state,-,sizeof(state));/*这是当时超时的点,第一次写数位dp,不知道只需初始化一次,然后放到了solve里,就。。。翻车了*/
while(~scanf("%d",&t))
{
while(t--)
{
scanf("%I64d%I64d",&l,&r);
printf("%I64d\n",solve(r)-solve(l-));
}
}
return ;
}

HDU 4352 XHXJ's LIS

DESC:把一个数看做字符串,那么它的最长上升子序列的长度就是这个数的power value。

问,在l 到r的区间内,power value等于k的数有多少个。

(0<L<=R<2^63-1 and 1<=K<=10)

思路:

开始我是这样的:

2^63大概是10^18,k<=10,dp[20][1200][10] //1024

dp[i][j][k]=num 表示前i位的最长递增子序列为j长度为k的数的个数为num个。

dfs(pos, stu, num, lim)时。对当前位pos尝试放1~mnum的数字d时,

比较stu和nstu = stu | (1<<d)的大小..如果nstu>stu,dfs(pos-1, nstu, num+1, newlim);

否则的话。说明新加的数使得当前序列分成了两个。进行2次dfs。

1:原来的dfs(pos-1, stu, num, newlim).

2:包括新的数的LIS序列:dfs(pos-1, newstu, newnum, newlim);

此时的newstu:对原来的stu进行一次num[pos]+1~9的与运算,和num[pos]或运算。同时计算出newnum.

bug1:1253这样搜索到的结果是2,125 和 123,所以单纯的这样记录状态也是不行的。所以第二维的状态改为:100101表示长度为x的LIS最后一位是y,

这样的话,125遇见3就会变成123了。

bug2:本来觉得len记录下当前的LIS长度会省一些重复计算,然而,状态和len相同时,k不同时返回的结果也应该是不同的,所以这个记忆化是错的。

于是就变成了这样:

int dp[20][1200][20]; //dp[i][j][k] = x 表示前i位 LIS状态为j 长度为k的 数字个数为 x

对当前的d,检查stu如果后面没有大于d的数,就直接newstu= stu | (1<<d)。否则,找出第一个大于d的数,删掉,然后或操作(1<<d),得到newstu。

前导0:检查当前d是前导0的时候,stu不变,继续搜索。

如果当前的数字出现过了,stu也不变,继续搜索。

【因为这次大腿也间歇性老年痴呆,两个人一起卡了两天晚上的几个点。最后一个bug:dp不是long long大腿找了一个点... ...感觉这个题A的也很感人,

青岛赛站结束是不是就不会这样写题了呢。有点舍不得。】

 //HDU 4352

 #include <stdio.h>
#include <string.h>
#include <iostream>
#define LL long long
using namespace std; int num[];
LL dp[][][]; //dp[i][j][k] = x 表示前i位 LIS状态为j 长度为k的 数字个数为 x LL dfs(int pos, int stu, int k, int lim) { //lim==1 表示当前位有限制
if (pos == -) {
int cnt = ;
for (int i=; i<=; ++i) {
if (stu & (<<i)) {
cnt++;
}
}
return (cnt == k);
}
if (!lim && dp[pos][stu][k] != -) return dp[pos][stu][k];
int mnum = (lim == ? : num[pos]);
LL sum = ;
for (int d=; d<=mnum; ++d) {
bool aft = false;
int tstu = stu;
bool pre = true;
if (d == ) {
for (int i=; i<=; ++i) {
if (tstu & (<<i)) pre = false;
}
if (pre) {
sum += dfs(pos-, stu, k, lim&&(d==mnum));
continue;
}
}
if (tstu & (<<d)) {
sum += dfs(pos-, stu, k, lim&&(d==mnum));
continue;
}
for (int i=d+; i<=; ++i) {
if (tstu & (<<i)) {
tstu = (stu ^ (<<i));
tstu |= (<<d);
aft = true;
break;
}
}
if (aft==false) { // 后面没有比他大的 可以直接加上
tstu = (stu | (<<d));
sum += dfs(pos-, tstu, k, lim&&(d==mnum));
}else sum += dfs(pos-, tstu, k, lim&&(d==mnum));
}
return (lim == ? dp[pos][stu][k] = sum : sum);
} LL solve(LL x, int k) {
if (x == ) return ;
int len = ;
while(x) {
num[len++] = x % ;
x /= ;
}
return dfs(len-, , k, );
} int main() {
// freopen("in.cpp", "r", stdin);
memset(dp, -, sizeof(dp));
int t;
scanf("%d", &t);
int cas = ;
while(t--) {
LL l, r;
int k;
scanf("%lld%lld%d", &l, &r, &k);
LL ans = solve(r, k) - solve(l-, k);
printf("Case #%d: %lld\n", cas++, ans);
}
return ;
}

数位DP入门的更多相关文章

  1. xbz分组题B 吉利数字 数位dp入门

    B吉利数字时限:1s [题目描述]算卦大湿biboyouyun最近得出一个神奇的结论,如果一个数字,它的各个数位相加能够被10整除,则称它为吉利数.现在叫你计算某个区间内有多少个吉利数字. [输入]第 ...

  2. 数位dp入门 hdu2089 不要62

    数位dp入门 hdu2089 不要62 题意: 给定一个区间[n,m] (0< n ≤ m<1000000),找出不含4和'62'的数的个数 (ps:开始以为直接暴力可以..貌似可以,但是 ...

  3. hdu3555 Bomb 数位DP入门

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555 简单的数位DP入门题目 思路和hdu2089基本一样 直接贴代码了,代码里有详细的注释 代码: ...

  4. HDU 2089 不要62【数位DP入门题】

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

  5. HDU 2089 不要62(数位dp入门)

    题意:统计区间 [a,b] 中不含 4 和 62 的数字有多少个. 题解:这是数位DP的入门题了,首先要理解数DP的原理,DP[i][j]:代表第i位的第j值,举个栗子:如4715   数位数是从右向 ...

  6. HDU 2089 - 不要62 - [数位DP][入门题]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089 Time Limit: 1000/1000 MS (Java/Others) Memory Li ...

  7. LightOJ 1140 计数/数位DP 入门

    题意: 给出a,b求区间a,b内写下过多少个零 题解:计数问题一般都会牵扯到数位DP,DP我写的少,这道当作入门了,DFS写法有固定的模板可套用 dp[p][count] 代表在p位 且前面出现过co ...

  8. HDU-2089不要62-暴力或数位DP入门

    不要62 题意:给定区间,求在这个区间中有多少个数字,不包含4且不包含62: 这道题作为数位DP的入门题: 暴力也是可以过 #include<cstdio> #include <io ...

  9. 数位dp入门 HDU 2089 HDU 3555

    最基本的一类数位dp题,题目大意一般是在a~b的范围,满足某些要求的数字有多少个,而这些要求一般都是要包含或者不包含某些数字,或者一些带着数字性质的要求,一般来说暴力是可以解决这一类问题,可是当范围非 ...

随机推荐

  1. Xamarin.Forms ListView点击按钮刷新最新数据

    最近在研究Xamarin的东西,做到ListView遇到了一些瓶颈,像在数据庞大的情况下,该怎么针对ListView中的数据分组呢? 基于能力有限的问题,暂时写了一个只可以实现功能的临时解决方案,毕竟 ...

  2. EF的性能改善和思考

    EF是个工具,用的好了性能就会很好,用的不好性能就会有很大损失. 先从EF的设计思想来讲解 EF的初衷是根据缓存中的实体对象,以及实体对象的状态(删除.更新.添加)来对数据库进行操作,这些实体对象.以 ...

  3. mac攻略(六) -- mac根目录分析

    根目录截图如下     符合unix传统的目录 /bin 传统unix命令的存放目录,如ls,rm,mv等. /sbin 传统unix管理类命令存放目录,如fdisk,ifconfig等等. /usr ...

  4. 【leetcode❤python】 204. Count Primes

    #-*- coding: UTF-8 -*- #Hint1:#数字i,i的倍数一定不是质数,因此去掉i的倍数,例如5,5*1,5*2,5*3,5*4,5*5都不是质数,应该去掉#5*1,5*2,5*3 ...

  5. JavaScript对象的chapterI

    对象: 对象就是由一些彼此相关的属性和方法集合在一起而构成的一个数据实体. 一.本地对象: 1.Date——日期对象 var myDate = new Date(); myDate.getFullYe ...

  6. javascript基础知识show

    1.javascript的数据类型是什么 基本数据类型:String,boolean,Number,Undefined,Null 引用数据类型:Object(Array,Date,RegExp,Fun ...

  7. phprpc的简单使用

    PHPRPC 是一个轻型的.安全的.跨网际的.跨语言的.跨平台的.跨环境的.跨域的.支持复杂对象传输的.支持引用参数传递的.支持内容输出重定向的.支持分级错误处理的.支持会话的.面向服务的高性能远程过 ...

  8. 【干货】微信场景之H5页面制作免费工具大集合

    营销代有手段出,各领风骚数百天.要说现在哪些营销方式最能传播,屡屡刷爆朋友圈的H5页面肯定就是首当其冲的,提到H5页面,就立马想到"围住神经猫",上线微信朋友圈3天的时间便创造了用 ...

  9. thinkphp的学习笔记

    # Thinkphp ## 什么是框架?(框架开发)> 框架就是通过提供一个开发Web程序的基本框架(比如提供了分页类.数据库操作类.文件操作类等),使用框架可以减少开发者代码的编写.> ...

  10. spring4+websocket+nginx详细配置

    实现的版本jdk1.7.0_25, tomcat7.0.47.0, Tengine/2.1.1 (nginx/1.6.2), servlet3.0, spring4.2.2 使用maven导入版本3. ...