首页 > 其他分享 >学习笔记:数位dp

学习笔记:数位dp

时间:2023-05-04 18:35:25浏览次数:45  
标签:sy mat int 笔记 && include dp 数位

1.基本模型

数位dp,即以数的每一位作为状态进行dp的算法。通常状态为 \(f_{i,0-9}\) 表示第 \(i\) 为取 \(0-9\) 时的dp值。通常时间复杂度为 \(log_{10}n\) ,十分优秀。

2.套路

  1. 求区间合法类的题,使用容斥思想思想求解,即 \([1,r]-[1,l-1]\)
  2. dp式子一般很简单,可以使用矩阵快速幂优化
  3. 前导0和值域限制需要单独dp可以再开一维 \(0/1\),表示当前 \(0\) 是否有是前导(即这一位是否有限制)。

3.例题

Windy数(套路1,3)

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#define mod 1000000007
#define int long long
using namespace std;
int l,r,f[10][10];
int get(int r)
{
	int sy[10],len=0,re=0;
	while(r)
	{
		sy[++len]=r%10; //拆位
		r/=10;
	}
	reverse(sy+1,sy+len+1);
	memset(f,0,sizeof(f));
	sy[0]=-3;
	bool nowJS=true;
	for(int i=1;i<=len;i++) //数位
	{
		for(int z=0;z<10;z++) //这一位
		{
			for(int j=0;j<=9;j++) //上一位
			{
				if(j>max(-1ll,z-2)&&j<min(10ll,z+2)) continue; //不在范围内
				f[i][z]+=f[i-1][j]; //统计
			}
			if(sy[i]>z&&abs(sy[i-1]-z)>=2&&i!=1){f[i][z]+=nowJS;} //破除值域限制
			else if(i==1&&sy[i]>z&&z!=0){f[i][z]+=nowJS;} //第一位特殊处理
			if(i!=1&&z!=0){f[i][z]++;} //破除前导0
		}
		if(abs(sy[i]-sy[i-1])<2){nowJS=false;} //维护极限值是否合法,用于值域限制
	}
	for(int i=0;i<10;i++)
	{
		re+=f[len][i];
	}
	return re+nowJS; //记得
}
signed main()
{
    cin>>l>>r;
    cout<<max(get(r)-get(l-1)+(l==1),0ll);
}

Sam数(套路2)

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#define mod 1000000007
#define int long long
using namespace std;
int n,ans;
struct mat
{
	int mat[12][12];
}a,c;
mat mult(mat a,mat b)
{
	mat c;
	memset(c.mat,0,sizeof(c.mat));
	for(int k=0;k<=9;k++)
	{
		for(int i=0;i<=9;i++)
		{
			for(int z=0;z<=9;z++)
			{
				c.mat[i][z]+=a.mat[i][k]*b.mat[k][z]%mod;
				c.mat[i][z]%=mod;
			}
		}
	}
	return c;
}
mat mul(mat a,mat b)
{
	mat c;
	memset(c.mat,0,sizeof(c.mat));
	for(int k=0;k<=9;k++)
	{
		for(int i=0;i<=9;i++)
		{
			for(int z=0;z<=9;z++)
			{
				c.mat[i][z]+=a.mat[i][k]*b.mat[k][z]%mod;
				c.mat[i][z]%=mod;
			}
		}
	}
	return c;
}
mat operator *(mat a,mat b)
{
	mat c;
	memset(c.mat,0,sizeof(c.mat));
	for(int k=0;k<=9;k++)
	{
		for(int i=0;i<=9;i++)
		{
			for(int z=0;z<=9;z++)
			{
				c.mat[i][z]+=a.mat[i][k]*b.mat[k][z]%mod;
				c.mat[i][z]%=mod;
			}
		}
	}
	return c;
}
mat operator ^(mat a,int b)
{
	//init
	mat re;
	memset(re.mat,0,sizeof(re.mat));
	for(int i=0;i<=9;i++)
	{
		re.mat[i][i]=1;
	}
	//ksm
	while(b)
	{
		if(b&1)
		{
			re=mul(re,a);
		}
		a=mul(a,a);
		b>>=1;
	}
	return re;
}
signed main()
{
    for(int i=1;i<=9;i++)
    {
        a.mat[1][i]=1;
    }
    cin>>n;
    for(int z=0;z<=9;z++)
    {
        for(int j=max(z-2,0ll);j<=min(9ll,z+2);j++)
        {
            c.mat[z][j]=1;
        }
    }
    a=mult(a,c^(n-1));
    for(int i=0;i<=9;i++)
    {
        ans=(ans+a.mat[1][i])%1000000007;
    }
    if(n>1)
    {
        cout<<ans;
    }
    else
    {
        cout<<ans+1;
    }
}

标签:sy,mat,int,笔记,&&,include,dp,数位
From: https://www.cnblogs.com/lizhous/p/17372172.html

相关文章

  • 线性基学习笔记
    概念线性基是一个集合。从原集合中选取任意数都能通过线性基中的数异或得到。本质上是对集合的压缩性质所有数字没有最高位相同的集合大小为\(\log_2\)级别。操作排查:若线性基内有最高位相等的,让其相异或,并继续排查直到没有可操作的数。若原集合内有\(0\)线......
  • 莫队学习笔记
    概念莫队是一种幽雅的暴力。用于处理区间问题。核心思想就是把询问离线下来,然后维护双指针按一定顺序处理每个询问。精髓就在于一定顺序。首先确定一个块长,然后将左端点的位置除以块长,把询问分成若干块。在每个块里按右端点排序。发现当块长为\(\sqrtn\)时两个指针各移动\(......
  • 后缀数组学习笔记
    概念后缀数组,即对于一个串,它的每个后缀按字典序排序后得到的数组。有两个数组要求:\(SA_i\):排名为\(i\)的后缀的开头位置\(RK_i\):以\(i\)为开头的后缀的排名朴素sort排序一下优化倍增优化:我们进行\(\logn\)次排序,第\(k\)次取所有后缀的前\(2^k\)个字符进行......
  • 点分治学习笔记
    概念点分治用于解决有一定要求的链的计数。对于点\(u\)的子树的问题,可以将答案分为:经过点\(u\)不经过点\(u\)第一种可以用桶加暴力。枚举一端的长度,用桶计算另一端长度;第二种分到子树中解决即可。注意到,在随机选根的时候该算法表现不优秀,但若根为重心,因为每次子树......
  • 网络流学习笔记
    概念最大流:在一个网络图上,每个边有流量限制,假如起始点有无线流量,求最多能有多少流量流到终点。增广路:一条从起始点到终点了路径,可以流流量。算法Ford-Fulkerson算法解决这个问题,可以用Ford-Fulkerson算法。该算法的核心就是寻找增广路。每找到一条增广路,就给它它能承受......
  • CentOS 下修改 WordPress 文件上传大小限制
    CentOS下可以通过修改php.ini来设置WordPress 文件上传大小限制。默认的php.ini文件是在/etc下。(对应的包:php-common)修改下面的几个参数:upload_max_filesize=64Mpost_max_size=64Mmax_execution_time=300修改后重启httpd。$servicehttpdrestart这样上传文......
  • CF708C Centroids(换根dp)
    题意:给定一颗树,你有一次将树改造的机会,改造的意思是删去一条边,再加入一条边,保证改造后还是一棵树。请问有多少点可以通过改造,成为这颗树的重心?(如果以某个点为根,每个子树的大小都不大于\(\dfrac{n}{2}\),则称某个点为重心)思路:是今天遇到的一道有意思的换根dp呃呃。从题意来看......
  • TypeScript 学习笔记 — 模板字符串和类型体操(十五)
    目录基本介绍字符串类型体操实操环节1.字符串首字母大写CapitalizeString2.获取字符串第一个字符FirstChar3.获取字符串最后一个字符LastChar4.字符串转元组StringToTuple5.元组转字符串TupleToString6.重复字符串RepeatString7.字符串分割SplitString8.获取字符串......
  • 配置wordpress:解决头像不显示问题(wordpress 6.2)
    一,默认头像效果:Gavatar的头像在国内不能正常访问,如图:二,设置:把以下php代码添加到模板函数funtions.php文件中if(!function_exists('get_cravatar_url')){/***把Gravatar头像服务替换为Cravatar*@paramstring$url*@returnstring*/......
  • react.js学习笔记
    (1)      参考文献1.前端技术手册2.在线编码......