[置顶] 数位DP 51Nod1009,hdu 4278,2089,3652,3555,4507,poj 3252
模板有2:
版1::
void init() {
dp[0][0] = 1;
for (int i = 1; i <=14 ; ++i)//第i位
for (int j = 0; j <= 9; ++j)//第i-1位的可能值
for (int k = 0; k <= 9; ++k)//第i位的可能值
if (j != 3 && j!=8)
dp[i][j] += dp[i - 1][k];
}同如上的三层循环,把每一位的所需情况遍历出来,直接满足条件时求和即可,适用于状态转移方程简单的情况板2::
static int dfs(int s,int m,int f,boolean u) {//s是当前位数,m,f或更多变量表示约束条件,u表示是否到达边界
if(s==0){
return m==0&&f==2?1:0;
}
if(!u&&dp[s][m][f]!=-1) {
return dp[s][m][f];
}
int len=u?dig[s]:9;//所取进位制(k进制),9处应该为k-1
int ans=0;
for(int i=0;i<=len;i++) {
int t=(m*10+i)%13;
int tf=f;
if(f==1&&i==3) {
tf=2;
}
else if(f==0&&i==1) {
tf=1;
}
else if(f==1&&i!=1) {
tf=0;
}
ans+=dfs(s-1,t,tf,u&&(i==len));//状态转移方程
}
if(!u) {
dp[s][m][f] = ans;
}
return ans;
}
static int cal(int n) {讲每一位储存到dig(位数)数组里面,根据进制选择不同,除数应发生变化
int k=0;
for(int i=0;i<15;i++)dig[i]=0;
while(n!=0) {
dig[++k]=n%10;
n/=10;
}
for(int i=0;i<15;i++) {
for(int j=0;j<15;j++) {
for(int r=0;r<15;r++) {
dp[i][j][r]=-1;
}
}
}
return dfs(k,0,0,true);
}这个板子的好处是灵活,可以应对基本所有的数位dp,只要设计好状态转移方程,选择合适的记录值创建dp数组,即可。
要理解的话,把上面那几个题搞出来就基本完事了
标题所示题目解答,按顺序如下
1009
import java.util.*;
public class Main{
static Scanner in=new Scanner(System.in);
public static void main(String[] args) {
// TODO Auto-generated method stub
while(in.hasNext()) {
long x=in.nextInt();
long a[]=new long[20];
long res=0;
int len=0;
long dig=0;
long rad=1;
long tail=0;
long t=1;
a[0]=0;
for (int i = 1; i <= 19; i++){
a[i]=a[i-1]*10+t;
t*=10;
}
while(x!=0) {
dig=x%10;
x/=10;
++len;
if(dig > 1) {
res+=rad+dig*a[len-1];
}
else if(dig==1) {
res+=tail+a[len-1]+1;
}
tail = tail + dig*rad;
rad*=10;
}
System.out.println(res);
}
}
}4278
import java.util.*;
public class Main {
//变量声明
static Scanner in=new Scanner(System.in);
static long dp[][]=new long[15][10];
static long d[]=new long [15];
static long x;
//初始化
static void init() {
dp[0][0] = 1;
for (int i = 1; i <=14 ; ++i)
for (int j = 0; j <= 9; ++j)
for (int k = 0; k <= 9; ++k)
if (j != 3 && j!=8)
dp[i][j] += dp[i - 1][k];
}
//数位dp
static long dp(long n) {
long ans = 0;
int len = 0;
while (n!=0) {
++len;
d[len] = n % 10;
n /= 10;
}
d[len + 1] = 0;
for (int i = len; i >= 1; --i) {
for (int j = 0; j < d[i]; ++j) {
ans += dp[i][j];
}
if (d[i]==3 || d[i]==8)
return ans;
}
return ans;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
init();
while(in.hasNext()) {
long x=in.nextLong();
if(0==x) {
break;
}
System.out.println(x+": "+dp(x));
}
}
}2089
import java.util.*;
public class Main {
//变量声明
static Scanner in=new Scanner(System.in);
static long dp[][]=new long[10][10];
static long d[]=new long [10];
static long x;
//初始化
static void init() {
dp[0][0] = 1;
for (int i = 1; i <= 7; ++i)
for (int j = 0; j <= 9; ++j)
for (int k = 0; k <= 9; ++k)
if (j != 4 && !(j == 6 && k == 2))
dp[i][j] += dp[i - 1][k];
}
//数位dp
static long dp(long n) {
int ans = 0;
int len = 0;
while (n!=0) {
++len;
d[len] = n % 10;
n /= 10;
}
d[len + 1] = 0;
for (int i = len; i >= 1; --i) {
for (int j = 0; j < d[i]; ++j) {
if (d[i + 1] != 6 || j != 2)
ans += dp[i][j];
}
if (d[i] == 4 || (d[i + 1] == 6 && d[i] == 2))
return ans;
}
return ans;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
init();
while(in.hasNext()) {
long x=in.nextLong(),y=in.nextLong();
if(0==x&&0==y) {
break;
}
System.out.println(dp(y+1)-dp(x));
}
}
}3652
import java.util.*;
public class Main {
static Scanner in=new Scanner(System.in);
static int dp[][][]=new int[15][15][15];
static int dig[]=new int[15];
static int dfs(int s,int m,int f,boolean u) {
if(s==0){
return m==0&&f==2?1:0;
}
if(!u&&dp[s][m][f]!=-1) {
return dp[s][m][f];
}
int len=u?dig[s]:9;
int ans=0;
for(int i=0;i<=len;i++) {
int t=(m*10+i)%13;
int tf=f;
if(f==1&&i==3) {
tf=2;
}
else if(f==0&&i==1) {
tf=1;
}
else if(f==1&&i!=1) {
tf=0;
}
ans+=dfs(s-1,t,tf,u&&(i==len));
}
if(!u) {
dp[s][m][f] = ans;
}
return ans;
}
static int cal(int n) {
int k=0;
for(int i=0;i<15;i++)dig[i]=0;
while(n!=0) {
dig[++k]=n%10;
n/=10;
}
for(int i=0;i<15;i++) {
for(int j=0;j<15;j++) {
for(int r=0;r<15;r++) {
dp[i][j][r]=-1;
}
}
}
return dfs(k,0,0,true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int n;
while(in.hasNext()) {
n=in.nextInt();
int x=cal(n);
System.out.println(x);
}
}
}
3555
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
__int64 dp[25][3];
void Init()
{
memset(dp,0,sizeof(dp));
dp[0][0] = 1;
int i;
for(i = 1;i<=22;i++)
{
dp[i][0] = dp[i-1][0]*10-dp[i-1][1];
dp[i][1] = dp[i-1][0];
dp[i][2] = dp[i-1][2]*10+dp[i-1][1];
}
}
__int64 solve(__int64 n)
{
__int64 i,tem = n,len = 0,a[25],flag = 0,ans = 0;
while(n)
{
a[++len] = n%10;
n/=10;
}
a[len+1] = 0;
for(i = len;i;i--)
{
ans+=dp[i-1][2]*a[i];
if(flag)
ans+=dp[i-1][0]*a[i];
if(!flag && a[i]>4)
ans+=dp[i-1][1];
if(a[i+1] == 4 && a[i] == 9)
flag = 1;
}
return ans;
}
int main()
{
int t;
__int64 n;
scanf("%d",&t);
Init();
while(t--)
{
scanf("%I64d",&n);
printf("%I64d\n",solve(n+1));
}
return 0;
}4507
#include "cstdio"
#include "math.h"
#include "cstring"
#define mod 1000000007LL
#define LL long long
struct status
{
LL cnt,sum,sqsum;
status() {cnt=-1;sum=sqsum=0;}
status(LL cnt,LL sum,LL sqsum):cnt(cnt),sum(sum),sqsum(sqsum) {}
}dp[20][10][10];
LL digit[20],p[25];
status dfs(int len,int re1,int re2,bool fp)
{
if(!len) return re1!=0&&re2!=0?status(1,0,0):status(0,0,0);
if(!fp&&dp[len][re1][re2].cnt!=-1) return dp[len][re1][re2];
int fpmax=fp?digit[len]:9;
status ans;ans.cnt=0;
for(int i=0;i<=fpmax;i++)
{
if(i==7) continue;
status next=dfs(len-1,(re1+i)%7,(re2*10+i)%7,fp&&i==fpmax);
ans.cnt+=next.cnt;
ans.cnt%=mod;
ans.sum+=(next.sum+((p[len]*i)%mod)*next.cnt%mod)%mod;
ans.sum%=mod;
ans.sqsum+=(next.sqsum+((2*p[len]*i)%mod)*next.sum)%mod;
ans.sqsum%=mod;
ans.sqsum+=((next.cnt*p[len])%mod*p[len]%mod*i*i%mod);
ans.sqsum%=mod;
}
if(!fp) dp[len][re1][re2]=ans;
return ans;
}
LL f(LL x)
{
int len=0;
while(x)
{
digit[++len]=x%10;
x/=10;
}
status tt=dfs(len,0,0,true);
return tt.sqsum;
}
int main()
{
int T;
LL l,r;
scanf("%d",&T);
p[1]=1;
for(int i=2;i<=20;i++) p[i]=(p[i-1]*10)%mod;
while(T--)
{
scanf("%I64d%I64d",&l,&r);
LL ans=f(r);
ans-=f(l-1);
printf("%I64d\n",(ans%mod+mod)%mod);
}
}3252
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int val[] = { 1,-1 };
int dig[40];
int dp[40][2][2][2][40];//位数,前面是否全是0,这一位是是谁,more 的正负,more 的绝对值
int a, b;
int sw(int site, bool r, int more, bool f) {
if (site == 0) {
//cout <<"ans:"<< more << endl;
return more >= 0?1:0;
}
if (!f&&dp[site][r][dig[site]][more>=0][abs(more)] != -1) {
return dp[site][r][dig[site]][more >= 0][abs(more)];
}
int len = f ? dig[site] : 1;
int ans = 0;
for (int i = 0; i <= len; i++) {
bool rr = r || i == 1;
int tem = rr?val[i]:0;
ans += sw(site - 1, rr,(more + tem), f && (i == len));
}
if (!f) {
dp[site][r][dig[site]][more >= 0][abs(more)] = ans;
}
return ans;
}
void deal() {
for (int i = 0; i < 40; i++) {
dig[i] = 0;
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 2; k++) {
for (int v = 0; v < 2; v++) {
for (int o = 0; o < 40; o++) {
dp[i][j][k][v][o] = -1;
}
}
}
}
}
int site = 0;
while (b != 0) {
dig[++site] = b % 2;
b /= 2;
}
int ans = sw(site, false,0, true);
--a;
site = 0;
for (int i = 0; i < 40; i++) {
dig[i] = 0;
}
while (a != 0) {
dig[++site] = a % 2;
a /= 2;
}
cout << ans - sw(site,false, 0, true);
}
int main(int argc, char *argv) {
ios::sync_with_stdio(false);
cin >> a >> b;
deal();
//cin >> a;
return 0;
}

浙公网安备 33010602011771号