美しい数字のCodeForces - 55D(数位DP)

タイトル

Volodyaは奇数少年であり、彼の味も同様に奇妙です。場合は正の整数が綺麗であることを彼に思えるし、それがその非ゼロの数字のそれぞれで割り切れる場合にのみ。私たちは、これを主張し、ただ与えられた範囲内の美しい数字の数をカウントされません。
入力

入力の最初の行はケースT(1≤T≤10)の数を含んでいます。次T線の各々は、二つの自然数LiとRI(1個の≤のLi≤RI≤9・1018)を含みます。

、C ++での64ビット整数を読み取りまたは書き込みに%のLLDのspecificatorを使用しないでください。(また、あなたが%I64dを使用することができます)CINを使用することを兼ね備えています。
出力

出力は、トン数が含まれている必要があります-クエリに対する回答を、1行に1つの番号-指定した間隔で美しい数字の量(RIに対するLiから、包括的に)。

入力

1
1 9

出力

9

入力

1つの
12 15
出力
2

問題の意味

区間番号の数に美しいL Rを探して、番号の各桁の値の数によって美しい数割り切れるが、美しさの数で定義されています。

思考

各桁の最小公倍数により数はすることができ、その組成割り切れる:それは美しい数に変換することができます。セットの数yは、そこにNビット(N <= 19)、ビットX1、百はX2にある、というように、最小公倍数LCM Xiに全てセットされ、きれいな条件数をy%のLCMに変換されます。 = 0。
DP、DP [POS] [和使用桁数 ] [LCM]は、元和のPOSビット、最小公倍数LCMの場合、アレイ美しい出会ういくつかの基準の数の組成を位置posを表します。
多額ため、実際には1-9の最小公倍数は2520年だったので、我々は結果が割り切れることができるかどうかに偏見なしに、残りの2520ペアの合計を飲み続けます。また、実際に最小公倍数LCMなし2520年のすべての数字は、ハッシュは、最小公倍数が全く比較はありませんどのくらいの値が区別さ、サイズの続きのように、異なるCONT〜9の数字1のいくつかの組み合わせに沿ったものである(それを維持します)を意味します。
;和%のLCMの寄与に対応する数が0と1であれば、DFSは、ある特定の数の代表的に0ないした出口
DP格納されたメモことが既知である場合、現在位置が制限されていない場合に直接使用することができ、一方空間が小さいの限定列挙である場合、予め記憶されたDPに等しくない場合、DPストレージが大きいサンプルにおいて、状態に制限されず、限定するものではないが、数が制限の場合よりもはるかに大きく見えます。

#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
ll dp[20][2521][50];
int hash[2521];
int dig[20];
int gcd(int a, int b){
	return b == 0 ? a:gcd(b, a%b);
}
int LCM(int a, int b){
	if(a == 0||b == 0)
		return a+b;
	return a*b/ gcd(a, b);
}
ll dfs(int pos, int sum, int lcm, int limit){
	if(pos == -1) return sum%lcm == 0?1:0;
	if(!limit && dp[pos][sum][hash[lcm]] != -1) return dp[pos][sum][hash[lcm]];
	int up = limit ? dig[pos]:9;
	ll ans = 0;
	int nsum = 0; int nlcm = 0;
	for(int i = 0; i <= up; i++){
		nsum = (sum*10+i)%2520;
		nlcm = LCM(i, lcm);
		ans += dfs(pos-1,nsum, nlcm, limit && i == up);
	}
	if(!limit) dp[pos][sum][hash[lcm]] = ans;
	return ans;
}
ll slove(ll x){
	int pos = 0;
	while(x){
		dig[pos++] = x%10;
		x /= 10;
	}
	ll ans = dfs(pos-1, 0, 1, 1);
	return ans;
}
int main(){
	int t, i;
	scanf("%d", &t);
	memset(dp, -1, sizeof(dp));
	int cont = 0;
	for(i = 1; i*i < 2520; i++){
		if(2520 % i == 0){
			hash[i] = cont++;
			hash[2520/i] = cont++;
		}
	}
	ll r,l;
	while(t--){
		scanf("%I64d %I64d", &l, &r);
		printf("%I64d\n", slove(r) - slove(l-1));
	}
	return 0;
}
公開された52元の記事 ウォンの賞賛2 ビュー864

おすすめ

転載: blog.csdn.net/qq_44714572/article/details/103206308