Beautiful numbers(记搜经典)

来源:互联网 发布:美工需要会什么软件 编辑:程序博客网 时间:2024/05/22 12:38

http://codeforces.com/contest/55/problem/D


这道题太经典了,佩服做出来的人。

思路:

1.一个数除以M_CLM的余数如果整除 LCM则整除LCM。

2.对含有的0~9数字进行位压缩。

3.通过映射将Map[ ]的值压缩,从而使用数组vis[ ][ ][ ]对应的LCM压缩,注意到0~9各种组合的LCM最多不超过50种(证明如下),否则内存消耗太多。

4.将LCM都用数组存起来,从而减少时间消耗。

证明LCM不足50种:

LCM总是由以下组合成:

2(个数): 0、1、2、3

3(个数):0、1、2

其余:0、5、7、5和7.

当都为0是LCM为1.

组合种树一共有  4*3*4=48(种)。


#include <cstdio>#include <cstring>#include <cstdlib>#include <string>#include <map>#include <iostream>#include <stdexcept>#include <cstddef>#include <algorithm>#include <vector>#include <numeric>#include <cctype>#define LL long long#define Endl endl#define INF 0x7fffffff//#define WJusing namespace std;const int M_LCM=2520;LL vis[20][50][2520];int yin[1<<9],shu[20],key[50];map<int,int> Map;int cnt=0;int gcd(int x,int y){return y==0?x:gcd(y,x%y);}int lcm(int x,int y){return x*y/gcd(x,y);}int MAP(int x){if(!Map.count(x)){Map[x]=cnt;key[cnt++]=x;}return Map[x];}void init(){for(int i=1;i<(1<<9);i++){int temp=1;for(int j=0;j<9;j++)if(i&(1<<j)) temp=lcm(temp,j+1);yin[i]=MAP(temp);}yin[0]=-1;}LL dfs(int wei,int mod,int s,int bian){int id=yin[s];if(wei==0){if(id!=-1&&mod%key[id]==0) return 1;return 0;}if(!bian&&vis[wei][id][mod]!=-1) return vis[wei][id][mod];int lim=bian?shu[wei]:9;LL ret=0;for(int i=lim;i>=0;i--){int bit;if(i==0) bit=0;else bit=1<<(i-1);int yu=(mod*10+i)%M_LCM;ret+=dfs(wei-1,yu,s|bit,bian&&i==lim);}if(!bian) vis[wei][id][mod]=ret;return ret;}LL solve(LL x){int d=0;while(x){shu[++d]=x%10;x/=10;}return dfs(d,0,0,1);}int main(int argc, char *argv[]){#ifdef WJ//freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);#endifLL l,r;int t;memset(vis,-1,sizeof(vis));init();scanf("%d",&t);while(t--){scanf("%I64d%I64d",&l,&r);printf("%I64d\n",solve(r)-solve(l-1));}return 0;}


0 0