数位dp

CodeForces - 55D(数位dp,离散化)

送分小仙女□ 提交于 2020-03-16 07:12:07
题目来源:http://codeforces.com/problemset/problem/55/D Volodya is an odd boy and his taste is strange as well. It seems to him that a positive integer number is beautiful if and only if it is divisible by each of its nonzero digits. We will not argue with this and just count the quantity of beautiful numbers in given ranges. Input The first line of the input contains the number of cases t ( 1 ≤  t  ≤ 10). Each of the next t lines contains two natural numbers l i and r i ( 1 ≤  l i  ≤  r i  ≤ 9 ·10 18 ). Please, do not use %lld specificator to read or write 64-bit integers in C++. It is preffered

HDU 3555 数位DP

核能气质少年 提交于 2020-03-15 11:27:17
题意,问1~n 有多少个数含有49. f[i][0]表示小于等于i位的不含有49数有几个。 f[i][1]表示小于等于i位的含有49的数有几个。 f[i][2]表示小于等于i位的不含有49,但是最高位是9的数有几个。 f[i][0]=f[i-1][0]+f[i-1][0]*9-f[i-1][2]; 第一个f[i-1][0]表示小于i位的所有数。f[i-1][0]*9表示i-1位的数,在第i位有9种可能。也可以理解成最高位可以是0,049就是一个两位数。 f[i][1]=f[i-1][1]*10+f[i-1][2]; f[i][2]=f[i-1][0]; 49,049,0049是不是重复算了?是的,是重复算了,但“重叠”是没有关系的。两位的时候49算作一次。三位的时候049算作一次,但是49这个数不算了,已被049替代。 如果n=34549,则可以把n分成几个部分,1~29999, 30000~33999, 34000~34499, 344500~344539, 344540~344548, 344549. 3* f[4][1] + 3*f[3][1] + 4*f[2][1] + 3*f[1][1] +8*f[0][1] 单独计数。 关于这个单独计数,有个tip。作一次n++,(n+1)这次单独计数就不用算了。 如果遇到n=491934,这样,某i位的前两位是49

数位dp回顾

自闭症网瘾萝莉.ら 提交于 2020-03-12 06:43:17
不会数位dp的同学点这里 数位dp教学 # include <bits/stdc++.h> using namespace std ; # define ll long long # define lb long double # define INF 0x3f3f3f3f const int maxn = 100035 ; const int mod = 1e6 + 7 ; int len ; ll dp [ 15 ] [ 2 ] [ 2 ] [ 12 ] [ 10 ] ; // dp[i][j][k][l][m]表示当前搜到第i位,且前导0与最高位限制状态为j和k, 且要统计的数字是l, 并且已经产生m个dig的答案 int a [ 15 ] ; // pos代表当前搜到第几位,lead表示有无前导0, limit表示当前位是有限制, dig表示要统计是的数字, sum表示已经产生的dig的数量 ll dfs ( int pos , int lead , int limit , int dig , int sum ) { if ( pos > len ) return sum ; // 如果搜完了所有位数则返回答案sum if ( ! limit && ! lead && dp [ pos ] [ lead ] [ limit ] [ dig ] [ sum ] != - 1

HDU 3555 数位dp

眉间皱痕 提交于 2020-03-11 21:53:01
Bomb Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others) Total Submission(s): 15072 Accepted Submission(s): 5441 Problem Description The counter-terrorists found a time bomb in the dust. But this time the terrorists improve on the time bomb. The number sequence of the time bomb counts from 1 to N. If the current number sequence includes the sub-sequence "49", the power of the blast would add one point. Now the counter-terrorist knows the number N. They want to know the final points of the power. Can you help them? Input The first line of input consists of an

SPOJ BALNUM Balanced Numbers(数位DP+状态压缩)题解

守給你的承諾、 提交于 2020-03-07 07:19:25
思路: 把0~9的状态用3进制表示,数据量3^10 代码: #include<cstdio> #include<map> #include<set> #include<queue> #include<cstring> #include<string> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #define ll long long const int N = 500+5; const int INF = 0x3f3f3f3f; using namespace std; int dp[22][60000]; //0 没出现,1 奇数,2 偶数 int dig[22]; int check(int sta){ for(int i = 0;i <= 9;i++){ int tmp = sta % 3; sta /= 3; if(i % 2 == 1 && tmp == 1) return 0; else if(i % 2 == 0 && tmp == 2) return 0; } return 1; } int news(int sta,int x){ int num[10]; for(int i = 0;i <= 9;i++){ num[i] = sta % 3; sta /= 3

hdu 3555 数位DP

岁酱吖の 提交于 2020-03-05 07:55:21
找0~n 有多少个含有49的数直接DP dp[i][j][k] 到第 i位 前面一位是j k是是否含有49了 随便记录一下就可以了 #include <iostream> #include<string.h> #include<stdio.h> using namespace std ; #define ll long long int dig[20]; ll dp[20][10][2]; ll dfs(int len,int now,int ok,int e) { if(len<0) return (ok==1); if(!e&&dp[len][now][ok]!=-1) return dp[len][now][ok]; int u=e?dig[len]:9; ll ans=0; for(int i=0;i<=u;i++) { if(now==4&&i==9) ans=ans+dfs(len-1,i,1,e&&(i==u)); else ans=ans+dfs(len-1,i,ok,e&&(i==u)); } if(!e) dp[len][now][ok]=ans; return ans; } ll calc(ll n) { int cnt=0; while(n) { dig[cnt++]=n%10; n=n/10; } return dfs(cnt-1,0,0,1); }

数位DP入门

浪子不回头ぞ 提交于 2020-03-05 06:58:54
考试考dp的时候时常会碰见有关数位dp的问题,每次考到就是一脸懵逼加吃惊,所以今天抽空看了一下有关数位dp的知识,网上有很多大神都说的很好,推荐看几篇blog。 入门经典 慢慢看,很不错 数位DP的套路 数位dp其实看了那么多篇blog感觉就是一个套路,一个记忆化搜索,方法无非是用两个端点的答案相减得到答案。dp主要考得是状态的设定和转移及其优化,对于数位dp来说,转移和优化其实是固定的,变的只是状态的设定,把状态设好了,套上板子处理下边界和正确性就好了,感觉还是要多做题,先贴两道题,之后慢慢更新,可以去vj上坐kuangbin带你飞系列的数位dp专题,题目很适合入门的人。 HDU2089 题面 统计区间 [a,b] 中不含 4 和 62 的数字有多少个。 分析 这其实是一道模板题看了上面两篇blog的做这题会很简单,部分注释写在代码里了。 /************************************************************************* > Author: Drinkwater > Created Time: 2017/8/24 21:55:11 ************************************************************************/ #include<iostream>

E. Segment Sum (数位DP)

我是研究僧i 提交于 2020-03-01 16:11:49
题目: 传送门 题意:问在区间 [ L, R ] 中使用的数字不超过 k 种的数的和是多少,例如区间 [ 10, 50 ] 中使用的数字不超过 1 种的数的和是 11 + 22 + 33 + 44 = 110.    1 <= L <= R < 1e18, 1 <= k <= 10, 输出答案对 998244353 取模。 题解:显然数位DP,不过这里要算的是数的和,不是数的个数,那我们再维护一个变量就行啦,维护一下每个位上的数的贡献。 #include <bits/stdc++.h> #define LL long long #define mem(i, j) memset(i, j, sizeof(i)) #define rep(i, j, k) for(int i = j; i <= k; i++) #define dep(i, j, k) for(int i = k; i >= j; i--) #define pb push_back #define make make_pair #define INF INT_MAX #define inf LLONG_MAX #define PI acos(-1) using namespace std; const int N = 1e6 + 5, mod = 998244353; int a[20]; int k; LL p[25]

hdu 3555 数位DP

烂漫一生 提交于 2020-02-28 12:03:56
这题完全是看解题报告做出来的,之前完全没有这样的思路, DP数组的含义还是挺好理解的,后面使用的时候反而是想了好久才理解…… /* * hdu3555/linux.cpp * Created on: 2011-8-30 * Author : ben */#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <algorithm>using namespace std;typedef long long I64;typedef unsigned long long U64;/* * dp[i][0]表示长度为i,不包含49的数字的个数 * dp[i][1]表示长度为i,不包含49但以9开头的数字的个数 * dp[i][2]表示长度为i,包含49的数字的个数 */U64 dp[21][3];char digit[25];void work();int main() {#ifndef ONLINE_JUDGE freopen("data.in", "r", stdin);#endif work(); return 0;}void init() { dp[0][0] = 1; dp[0][1] = 0; dp[0][2] = 0; for(int i = 1; i < 20; i++) {

数位dp

自闭症网瘾萝莉.ら 提交于 2020-02-25 00:33:28
bzoj3679 数字之积 题目大意:给定n、l、r,f(i)表示i的各位数字之积(不含前导0),求出0<f(i)<=n(l<=i<r)的个数。 思路:这是在夏令营中学长讲的题目,听到一种相对简单的方法。很显然要用1~r的个数-1~l的个数我们先用2、3、5、7(因为每一位都是0~9,所以只能有这几种质数乘起来)dfs出可能的乘积,放在一个数组num中,用f[i][j]表示i位数字(不含前导0)乘积在数组中的下表j的方案数,更新时,用能整除num[j]的k在num中的位置对应的f[i-1][pok]更新答案,然后把这个f数组做成前缀和,就表示下标对应数字<=j的个数了。然后就是数位的部分,把这个数分成一位一位的,首先把长度比这个数小的所有方案都加起来,然后考虑长度一样的,每次穷举严格小于这一位的数,找到可用的乘积在num中的位置,然后加给答案,每一位结束后,就将n除以这一位上的原数。这里有一个问题,就是0,如果这一位是0我们就直接break掉就可以了,因为后面不会有满足要求的答案了(乘起来肯定是0,不符合要求)。 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; LL num[100000]={0},f