数位DP Ⅱ

本节题目:数位之间和的关系。一般需要多加一维状态f[i][j][k]:表示长度为i,第一位是i,数位和等于k的数列个数

Seven Segment Display

题意:每个数字都有一个对应的权值,求l~r(十六进制数)之间所有数的所有数字的权值和
预处理数组有点麻烦,f[i][j]表示长度为i,第一个数是j的所有数列的数位之和的总和,f[i][j]=f[i-1][0~15]+j*(长度为i-1的数列个数即pow(16,i-1)).
dp枚举第i位的数字时统计时还要算上last*(长度为i-1的数列的个数pow(16,i-1)).

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=20;
LL f[N][N];
int s[]={6,2,5,5,4,5,6,3,7,6,6,5,4,5,5,4};
int power[20];
LL dp(LL n){
	if(n==0) return s[0]*8;
	vector<int> nums;
	for(int i=1;i<=8;++i){
		nums.push_back(n%16);
		n/=16;
	}
	LL res=0,last=0;
	for(int i=nums.size()-1;i>=0;--i){
		int x=nums[i];
		for(int j=0;j<x;++j){
			res+=f[i+1][j]+power[i]*last;
		}
		last+=s[x];
	}
	res+=last;
	return res;
}
int main(){
	power[0]=1;
	for(int i=1;i<=10;++i) power[i]=power[i-1]*16;
	int res=0,p=16;
	for(int i=0;i<16;++i) f[1][i]=s[i],res+=s[i];//cout<<res<<endl;
	for(int i=2;i<9;++i,p*=16){
		for(int j=0;j<16;++j){
			f[i][j]=s[j]*p;
			for(int k=0;k<16;++k){
				f[i][j]+=f[i-1][k];
			}
		}
	}
	res=0;
	int T;
	cin>>T;
	while(T--){
        LL n,m,t=0xFFFFFFFF;
	    scanf("%lld%llX",&n,&m);
        LL l=m;
        LL r=m+n-1;
        if(r>t)
            cout<<dp(t)+dp(r%(t+1))-(l==0?0:dp(l-1))<<endl;
        else cout<<dp(r)-(l==0?0:dp(l-1))<<endl;
	}
	return 0;
}

1084. 数字游戏 II

由于科协里最近真的很流行数字游戏。
某人又命名了一种取模数,这种数字必须满足各位数字之和 mod N 为 0。
现在大家又要玩游戏了,指定一个整数闭区间 [a.b],问这个区间内有多少个取模数。
输入格式
输入包含多组测试数据,每组数据占一行。
每组数据包含三个整数 a,b,N。
输出格式
对于每个测试数据输出一行结果,表示区间内各位数字和 mod N 为 0 的数的个数。
数据范围
1≤a,b≤2^31−1,
1≤N<100
输入样例:
1 19 9
输出样例:
2

f[i][j][k] 长度为i 第一位是i 数位和%m等于k。注意(少生孩子)多取模!
eg:(a-b+c)%c一样可能小于0 ,应该是((a-b)%c+c)%c

#include<bits/stdc++.h>
using namespace std;
const int N=20,M=110;
int f[N][N][M]; //f[i][j][k] 长度为i 第一位是i 数位和%m等于k
int mod(int x,int p){
    return (x%p+p)%p;
}
void init(int m){
    memset(f,0,sizeof f);
    for(int i=0;i<10;++i) f[1][i][i%m]++;
    for(int i=2;i<N;++i){
        for(int j=0;j<10;++j){
            for(int k=0;k<10;++k){
                for(int r=0;r<m;++r){
                    f[i][j][r]+=f[i-1][k][mod(r-j,m)];
                }
            }
        }
    }
}
int dp(int num,int m){
    if(num==0) return 1;
    vector<int> nums;
    while(num) nums.push_back(num%10),num/=10;
    int res=0,last=0;
    for(int i=nums.size()-1;i>=0;--i){
        int x=nums[i];
        for(int j=0;j<x;++j){
            res+=f[i+1][j][mod(m-last,m)];
        }
        last+=x;
        if(i==0&&last%m==0) res++;
    }
    return res;
}
int main(){
    int l,r,k;
    while(cin>>l>>r>>k){
        init(k);
        cout<<dp(r,k)-dp(l-1,k)<<endl;
    }

}

1086. 恨7不成妻

单身!
依然单身!
吉哥依然单身!
DS 级码农吉哥依然单身!
所以,他平生最恨情人节,不管是 214 还是 77,他都讨厌!
吉哥观察了 214 和 77 这两个数,发现:
2+1+4=7
7+7=7×2
77=7×11
最终,他发现原来这一切归根到底都是因为和 7 有关!
所以,他现在甚至讨厌一切和 7 有关的数!
什么样的数和 7 有关呢?
如果一个整数符合下面三个条件之一,那么我们就说这个整数和 7 有关:
整数中某一位是 7;
整数的每一位加起来的和是 7 的整数倍;
这个整数是 7 的整数倍。
现在问题来了:吉哥想知道在一定区间内和 7 无关的整数的平方和。
输入格式
第一行包含整数 T,表示共有 T 组测试数据。
每组数据占一行,包含两个整数 L 和 R。
输出格式
对于每组数据,请计算 [L,R] 中和 7 无关的数字的平方和,并将结果对 109+7 取模后输出。
数据范围
1≤T≤50,
1≤L≤R≤1018
输入样例:
3
1 9
10 11
17 17
输出样例:
236
221
0

我们要找的数需要满足三个性质,1.不含7 2.数字和%7不等于0 3.数%7不等于0,所以我们的预处理数组需要是个状态f[i][j][a][b]:长度为i,最高位是j,数字之和%7是a,数%7是b。f[i][j][a][b] 由(f[i-1][0,1,2,3,4,5,6,8,9][a-j*10)(i-1)(][b-j])转移得到
然后这道题问的是所有数的立方和。假设我们枚举到第i位前面last,当前位枚举位j,那么就是立方和就是(jA_1^2+jA_2^2+...+jA_t^2=j×10)i-1(^2×t+2×j×10)(i-1)(×(A_1+A_2+...+A_t)+(A_1^2+A_2^2+...+A_t^2))
所以需要维护三个值,即(t=s0=A_1^0+A_2^0+...+A_t^0),(s1=A_1^1+A_2^1+...+A_t^1),(s2=A_1^2+A_2^2+...+A_t^2)
(s0)直接统计个数即可求,(s1=jA_1+jA_2+...+jA_t=j×10)(i-1)(×t+(A_1^1+A_2^1+...+A_t^1))
注意(少生孩子)多取模!

#include<bits/stdc++.h>
using namespace std;
const int N=21;
const int P=1e9+7;
#define int long long
typedef long long LL;
struct F{
    int s0,s1,s2;
}f[N][N][N][N];
int mod(int x,int y){
    return (x%y+y)%y;
}
int power7[N],power9[N];
void init(){
    for(int i=0;i<10;++i){
            if(i==7) continue;
            auto& v =f[1][i][i%7][i%7];
            v.s0++;v.s1+=i;v.s2+=i*i%P;
            v.s0%=P;v.s1%=P;v.s2%=P;
    }
    LL power=10;
    for(int i=2;i<N;++i,power*=10){
        for(int j=0;j<10;++j){
            if(j==7) continue;
            for(int a=0;a<7;++a){
                for(int b=0;b<7;++b){
                    for(int k=0;k<10;++k){
                        if(k==7) continue;
                        auto& v1=f[i][j][a][b],v2=f[i-1][k][mod(a-j*power,7)][mod(b-j,7)];
                        v1.s0=mod(v1.s0+v2.s0,P);
                        v1.s1=mod(v1.s1+(v2.s1+j*(power%P)%P*v2.s0%P)%P,P);
                        v1.s2= mod(v1.s2+(j*j%P*(power%P)%P*(power%P)%P*v2.s0%P
                            +2*j*(power%P)%P*v2.s1%P
                            +v2.s2),P);
                    }
                }
            }
        }
    }
    power7[0]=power9[0]=1;
    for(int i=1;i<N;++i){
        power7[i]=power7[i-1]*10%7;
        power9[i]=power9[i-1]*10%P;
    }
}
F get(int i,int j,int a,int b){
    int ss0,ss1,ss2; ss0=ss1=ss2=0;
    for(int aa=0;aa<7;++aa){
        for(int bb=0;bb<7;++bb){
            if(aa==a||bb==b) continue;
            ss0+=f[i][j][aa][bb].s0;ss0%=P;
            ss1+=f[i][j][aa][bb].s1;ss1%=P;
            ss2+=f[i][j][aa][bb].s2;ss2%=P;
        }
    }//cout<<i<<" "<<j<<" "<<a<<" "<<b<<" "<<" "<<s0<<" "<<s1<<" "<<s2<<endl;
    return (F){ss0,ss1,ss2};
}
signed dp(LL t){
    if(t==0) return 0;
    LL tt=t;
    vector<int> nums;
    while(tt) nums.push_back(tt%10),tt/=10;
    LL last_a=0,last_b=0,res=0;
    for(int i=nums.size()-1;i>=0;--i){
        int x=nums[i];
        for(int j=0;j<x;++j){
            if(j==7) continue;
            int a=mod(-last_a*power7[i+1],7),b=mod(-last_b,7);
            auto it=get(i+1,j,a,b);
            int s0=it.s0,s1=it.s1,s2=it.s2;
           // cout<<1+i<<" "<<j<<" "<<a<<" "<<b<<" "<<s0<<" "<<s1<<" "<<s2<<" "<<power9[i+1]<<" "<<last_a<<endl;
            res=mod(res+((last_a%P)*(power9[i+1]%P)%P*(last_a%P)%P*(power9[i+1]%P)%P*s0%P
                +2*(last_a%P)*(power9[i+1]%P)%P*s1%P
                +s2),P);
        }

        if(x==7) break;
        last_a=last_a*10+x;
        last_b+=x;
        if(i==0&&last_b%7&&last_a%7) res=mod(res+((t%P)*(t%P))%P,P);//cout<<t<<" "<<res<<endl;
    }
    return res%P;
}
signed main(){
    init();
    int T;
    cin>>T;
    while(T--){
        int a,b;
        cin>>a>>b;
        cout<<mod(dp(b)-dp(a-1),P)<<endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/jjl0229/p/12660497.html