很久以前做过的一道数位DP,现在用一种新的解决数位DP的比较一般的方法。

数位DP裸题是:求[L,R]有多少个数。

先转化成求[0,R]有多少个数,然后区间相减即可。

对于[0,R]中的所有数,用0补齐前面的空位,使得每个数的长度都为R的长度。

状态:

dp[pos][0]表示从最高位到pos位,没有顶上界的数的个数

dp[pos][1]表示从最高位到pos位,顶到上界的数的个数(好吧,这个问题中,它一定为1)

然后考虑转移,

dp[pos][0]->dp[pos-1][0](通过枚举pos-1位的数进行转移)

dp[pos][1]->dp[pos-1][0](通过枚举pos-1位,小于该位上界的数进行转移)

dp[pos][1]->dp[pos-1][1](只能在pos-1位填1)

顺推倒推都可以。

dp[1][0]+dp[1][1]就是答案。

对于其它的数位DP,都可以在这个DP上加上需要的状态维,然后解决其它问题。

上面的dp[pos][1]看似没有用(因为始终为1),但是实际上,我们是必须要它的,比如这道题。

我们设dp[pos][top][tail]表示:“比pos高的位,顶上界(top为1)或不顶上界(top为0),最后一位为tail的数的个数(并且要求这个数不为0)“

然后自己YY转移吧(这个不为0的要求和上一道题有点不同,具体看代码)。

新方法:

 /**************************************************************
Problem: 1026
User: idy002
Language: C++
Result: Accepted
Time:0 ms
Memory:808 kb
****************************************************************/ #include <cstdio>
#include <cstring>
#define abs(a) ((a)>0?(a):-(a)) typedef long long poi; poi lf, rg;
int aa[], tot;
poi dp[][][]; poi calc( poi v ) { // v in [1,oo)
for( tot=; v; v/= )
aa[++tot]=v%;
memset( dp, , sizeof(dp) );
dp[tot][][aa[tot]] = ;
for( int i=; i<aa[tot]; i++ )
dp[tot][][i] = ;
for( int i=tot; i>=; i-- ) {
for( int c=; c<=; c++ )
for( int s=; s<=; s++ )
if( abs(s-c)>= )
dp[i-][][s] += dp[i][][c];
for( int s=; s<=; s++ )
dp[i-][][s]++;
for( int s=; s<aa[i-]; s++ )
if( abs(s-aa[i])>= )
dp[i-][][s] += dp[i][][aa[i]];
dp[i-][][aa[i-]] = dp[i][][aa[i]] && abs(aa[i]-aa[i-])>=;
}
poi rt=dp[][][aa[]];
for( int i=; i<=; i++ )
rt += dp[][][i];
return rt;
}
int main() {
scanf( "%lld%lld", &lf, &rg );
printf( "%lld\n", calc(rg)-(lf==?:calc(lf-)) );
}

以前的:

 /**************************************************************
Problem: 1026
User: idy002
Language: C++
Result: Accepted
Time:0 ms
Memory:804 kb
****************************************************************/ #include <cstdio>
#include <algorithm>
using namespace std; struct Form {
int n;
int b[];
int src;
Form( int a ) {
n = ;
src = a;
if( a== ) {
n=;
b[] = ;
return;
}
while( a ) {
b[++n] = a%;
a/=;
}
}
};
int dp[][]; // dp[0~9][0~10] void init() {
for( int h=; h<=; h++ )
dp[h][] = ;
for( int l=; l<=; l++ )
for( int h=; h<=; h++ )
for( int g=; g<=; g++ )
if( abs(g-h)>= )
dp[h][l] += dp[g][l-];
} int calc( const Form &fm) { // [0,fm.src)
int ans = fm.src!=; //
for( int l=; l<fm.n; l++ )
for( int h=; h<=; h++ ) {
ans += dp[h][l];
//printf( "(h=%d,l=%d)\n", h, l );
}
for( int h=; h<fm.b[fm.n]; h++ ) {
ans += dp[h][fm.n];
//printf( "(h=%d,l=%d)\n", h, fm.n );
}
for( int l=fm.n-; l>=; l-- ) {
for( int h=; h<fm.b[l]; h++ )
if( abs(h-fm.b[l+])>= ) {
ans += dp[h][l];
//printf( "(h=%d,l=%d)\n", h, l );
}
if( abs(fm.b[l]-fm.b[l+])< ) break;
}
return ans;
} int main() {
// freopen( "windy.in", "r", stdin );
// freopen( "windy.out", "w", stdout );
int A, B, ans;
init();
scanf( "%d%d", &A, &B );
ans = calc(Form(B+))-calc(Form(A));
printf( "%d\n", ans );
}

  

bzoj 1026的更多相关文章

  1. [BZOJ 1026] [SCOI 2009] Windy数 【数位DP】

    题目链接:BZOJ - 1026 题目分析 这道题是一道数位DP的基础题,对于完全不会数位DP的我来说也是难题.. 对于询问 [a,b] 的区间的答案,我们对询问进行差分,求 [0,b] - [0,a ...

  2. [bzoj 1026]windy数(数位DP)

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1026 分析: 简单的数位DP啦 f[i][j]表示数字有i位,最高位的数值为j的windy数总 ...

  3. bzoj 1026 [SCOI2009]windy数 数位dp

    1026: [SCOI2009]windy数 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline ...

  4. BZOJ 1026 windy数

    Description windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道,在A和B之间,包括A和B,总共有多少个windy数? In ...

  5. bzoj 1026 [SCOI2009]windy数(数位DP)

    1026: [SCOI2009]windy数 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 4550  Solved: 2039[Submit][Sta ...

  6. BZOJ 1026: [SCOI2009]windy数( dp )

    dp..dp(x, t) 表示共x位, 第x位为t有多少个windy数. 对答案差分, 我们只需统计1 ~ l-1和1 ~ r的windy数数量. 考虑如何计算[1, n]的答案 : 从最高位到最低位 ...

  7. BZOJ 1026 windy数【数位DP】

    1026: [SCOI2009]windy数 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 10142  Solved: 4712[Submit][St ...

  8. bzoj 1026 DP,数位统计

    2013-11-20 08:11 原题传送门http://www.lydsy.com/JudgeOnline/problem.php?id=1026 首先我们用w[i,j]表示最高位是第i位,且是j的 ...

  9. bzoj 1026: [SCOI2009]windy数【数位dp】

    忘记limit不能记WA了一发-- 典型数位dp,变成work(r)-work(l-1),然后dfs的时候记录w当前位置,la上一个数选的什么,lm当前位是否有上限,ok当前位是否可以不考虑差大于等于 ...

随机推荐

  1. Ajax+innerHTML+Dgls=好的用户体验+高性能+高效率

    为了引入Dgls,我们从创建Dom节点说起. 用JS创建Dom节点 var div = document.createElement('div'); div.className = 'gdls'; v ...

  2. docker 镜像导入和导出

    使用 docker commit 即可把这个容器变为一个镜像 docker commit 8d93082a9ce1 ubuntu:myubuntu 这时候 docker 容器会被创建为一个新的 Ubu ...

  3. NEO发行资产Token

    NEO注册发行全局资产(Token 和 Share)功能已经在neo-gui里面集成,发行非常方便, 高级-注册资产 注册Token消耗GAS感人 4990 Gas 点击调用,获取交易ID为资产ID ...

  4. NuGet Package Explorer上传时报:failed to process request:'Method Not Allowed'错误解决办法

    相关日志:PUT /api/v2/package - 1000 -  NuGet+Package+Explorer/3.15.0.0+(Microsoft+Windows+NT+6.2.9200.0) ...

  5. centos7下vi的用法

    vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令.由于对Unix及Linux系统的任何版本,vi编辑器是完全相 ...

  6. curl基于URL的文件传输工具

    简介 cURL是一款开源的基于URL的文件传输工具,支持HTTP.HTTPS.FTP等协议,支持POST.cookie.认证.扩展头部.限速等特性. curl命令用途广泛,比如下载.发送http请求. ...

  7. python开发web服务器——搭建简易网站

    参看:https://blog.csdn.net/baidu_35085676/article/details/69807145

  8. leetcode 之Longest Consecutive Sequence(六)

    这题要仔细体会下哈希表的用法,要注意的是数组本身是无序的,因此需要向左右进行扩张. 另外这个思路可以进行聚类,把连续的标记为一类. int longestConsecutive(const vecto ...

  9. 实习day2:@2X图片,git,coding.net,

    @2X是5和6系列的图片,@3X是6P等大屏的图片 本公司目前只用@2X的图片适配. 比如20X27的图片 1x, 就是原始大小: 用2X, 就除以2,变成10X13.5: 如果用3X的, 就除以3, ...

  10. 应用nslookup命令查看A记录、MX记录、CNAME记录和NS记录

    https://blog.csdn.net/qq_38058202/article/details/80468688