Codeforces 55D Beautiful numbers

題目鏈接:http://codeforces.com/contest/55/problem/D

題目簡述:求[a,b]區間內整數n,n能被他所有非零數位上的數整除。


看見整除,肯定想的就是%i=0,所以要記他%1~9的餘數,但這明顯是不科學的。。

於是乎,只需要記下1~9的LCM,LCM=2520,這樣狀態就小了很多了,到最後再分開模。

但是我怎麼知道他有1~9中的哪些?。。可以考慮狀壓,其實挺好。

但還有更好的方法,就是再記錄一個選中的數的LCM,剛剛%2520的數再來模這個LCM如果是0那麼肯定就對了。反之亦然。

1~9選出一些數的LCM其實只有48個,這樣複雜度又壓了很多。

狀態就是F[i][MOD][LCM]


記憶化搜索真心很無腦啊,隨便搞搞,邊界條件設一下就等他自己跑就行了。。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define rep(i,l,r) for (int i=l;i<=r;++i)
typedef long long LL;
const int MOD=2520;
int LCM[2521],num=0;
LL f[20][2521][49],a[20];
LL pow[20];
int Gcd(int a,int b){return !b?a:Gcd(b,a%b);}
int Lcm(int a,int b){return a*b/Gcd(a,b);}
void Prep(){
	memset(f,-1,sizeof f);
	pow[1]=1;
	rep(i,2,20) pow[i]=pow[i-1]*10%MOD;
	rep(i,1,MOD) if (MOD%i==0) LCM[i]=++num;
}
LL dfs(int pos,int mod,int lcm,bool lim){
	if (pos==0) return mod%lcm==0;
	if (!lim&&~f[pos][mod][LCM[lcm]]) return f[pos][mod][LCM[lcm]];
	int top=lim?a[pos]:9;LL res=0;
	rep(i,0,top){
		if (i==0) res+=dfs(pos-1,mod,lcm,lim&&i==top);
		else{
			int M=(mod+pow[pos]*i)%MOD;
			res+=dfs(pos-1,M,Lcm(lcm,i),lim&&i==top);
			}
		}
	return lim?res:(f[pos][mod][LCM[lcm]]=res);
}
LL count(LL x){
	int len=0;
	while (x) a[++len]=x%10,x/=10;
	return dfs(len,0,1,1);
}
int main(){
	Prep();
	int T;scanf("%d",&T);
	while (T--){
		LL l,r;
		scanf("%I64d%I64d",&l,&r);
		printf("%I64d\n",count(r)-count(l-1));
		}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章