HDU4507 恨7不成妻【数位dp】

传送门


思路:
比较基础的一道数位dp,只是平方和的维护要思考一下

loc: 当前位置
q:当前数位的数字
a:之前满足条件的数
b:当前满足条件的数
b = q ∗ 1 0 l o c − 1 + a b= q*10^{loc-1}+a b=q10loc1+a
b 2 = ( q ∗ 1 0 l o c − 1 + a ) 2 b^2=(q*10^{loc-1}+a)^2 b2=(q10loc1+a)2

∑ ( a + b ) 2 = ∑ a 2 + ∑ b 2 + ∑ 2 ∗ a ∗ b \sum (a+b)^2=\sum a^2+ \sum b^2+ \sum 2*a*b (a+b)2=a2+b2+2ab

m:满足条件的数的个数
s:所有满足条件的数的总和
Ps:所有满足条件的数的平方和

P s [ l o c ] = P s [ l o c − 1 ] + m [ l o c − 1 ] ∗ q 2 + 2 ∗ q ∗ s [ l o c − 1 ] Ps[loc]= Ps[loc-1]+m[loc-1]*q^2+2*q*s[loc-1] Ps[loc]=Ps[loc1]+m[loc1]q2+2qs[loc1]
(注意取模)


代码:

#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define pf printf
#define int long long
const int mod=1e9+7;
struct node{
	int m,s,p;
	node operator +(const node & t ) const{
		return node((m+t.m)%mod,(s+t.s)%mod,(p+t.p)%mod);
	}
	node (int m=-1,int s=-1,int p=-1): m(m),s(s),p(p) {}
}f[20][10][10];
int bit[20],top=0,fc[20];
inline node update(node t,int q){
//	pf("t   m: %d s: %d p:%d q:%d \n",t.m,t.s,t.p,q);
	node ret;
	ret.m=t.m;
	ret.s= (q*t.m%mod+t.s)%mod;
	ret.p=t.p+t.m*(q*q%mod)%mod+2*t.s*q%mod;
	ret.p%=mod;
//	pf("ret m: %d s: %d p:%d q:%d \n",ret.m,ret.s,ret.p,q);
//	cout<<"\n";
	return ret;
}
inline node check(int sm,int om){
	if(sm%7!=0&&om%7!=0){
		return node(1,0,0);
		//return node(1,ori,ori*ori%mod);
	}
	return node(0,0,0);
}
inline node dfs(int loc,int sm,int om,bool up){
//	pf("loc: %d sm: %d om: %d up:%d ori: %d\n",loc,sm,om,up,ori);
	if(loc==0) return check(sm,om);
	if(!up&&(f[loc][sm][om].m!=-1))return f[loc][sm][om];
	node ret;ret.m=ret.s=ret.p=0;
	int mx=(up)? bit[loc] : 9;
	for(int i=0;i<=mx;++i){
		if(i==7)continue;
		ret=ret+update(dfs(loc-1,(sm+i)%7,(om*10+i)%7,up&&i==mx),i*fc[loc-1]%mod);
//		pf("loc: %d round : %d \n ret m: %d s: %d p:%d \n",loc,i,ret.m,ret.s,ret.p);
	}
	return (up) ?  ret  :  f[loc][sm][om]=ret; 
}
inline int work(int R){
	top=0;
	while(R)bit[++top]=R%10,R/=10;
	return dfs(top,0,0,1).p;
}
signed main(){
	int t,l,r;sf("%I64d",&t);
	fc[0]=1;for(int i=1;i<=18;++i) fc[i]=fc[i-1]*10;
	while(t--){
		sf("%I64d%I64d",&l,&r);
		cout<<(work(r)-work(l-1)+mod)%mod<<"\n";
	}
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值