[CodeForces-55D]Beautiful Numbers


題目大意:
  問區間[l,r]內有多少正整數能被其各個數位上的所有數字整除。

思路:
  數位DP。
  能被所有數位整除相當於能被所有數位的LCM整除。
  而1..9的LCM為2520。
  f[i][j][k][flag]表示DP到第i位,當前構成的數字在%2520意義下為j,當前各個數位的LCM為k,flag表示當前數是否為邊界。
  第三維的k顯然不會完全用到,事實上只會有48個可能的值,因此可以離散化。
  枚舉當前數位p,設邊界數的當前數位為cur,則轉移方程為:
  f[i-1][(j*10+p)%SUM][mult[k][p-1]][false]+=f[i][j][k][false];
  f[i-1][(j*10+p)%SUM][mult[k][p-1]][false]+=f[i][j][k][true];(p<cur)
  f[i-1][(j*10+p)%SUM][mult[k][p-1]][true]+=f[i][j][k][true];(p==cur)
  壓一下內存,可以用滾動數組。
  然而交上去發現會在第11個點TLE。
  試了各種奇怪的方法,並沒有什么用。
  還發現不開優化跑40s的數據,開了O1只需要跑3s。
  最后開性能分析,發現是在lcm的地方花了很多時間。
  於是先打表出所有的LCM,然后就過了。
  (然而51Nod上是10000組數據,不用記憶化搜索根本過不了)

 1 #include<cstdio>
 2 #include<algorithm>
 3 using std::__gcd;
 4 typedef unsigned long long qword;
 5 inline qword getint() {
 6     register char ch;
 7     while(!__builtin_isdigit(ch=getchar()));
 8     register qword x=ch^'0';
 9     while(__builtin_isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
10     return x;
11 }
12 const int SUM=2520,LCM=48;
13 const qword pow[]={1ull,10ull,100ull,1000ull,10000ull,100000ull,1000000ull,10000000ull,100000000ull,1000000000ull,10000000000ull,100000000000ull,1000000000000ull,10000000000000ull,100000000000000ull,1000000000000000ull,10000000000000000ull,100000000000000000ull,1000000000000000000ull,10000000000000000000ull};
14 int id[SUM+1];
15 const int mul[]={1,2,3,4,5,6,7,8,9,10,12,14,15,18,20,21,24,28,30,35,36,40,42,45,56,60,63,70,72,84,90,105,120,126,140,168,180,210,252,280,315,360,420,504,630,840,1260,2520};
16 inline int lcm(const int &a,const int &b) {
17     return a/__gcd(a,b)*b;
18 }
19 int mult[LCM][LCM];
20 inline void init() {
21     for(register int i=0;i<LCM;i++) {
22         id[mul[i]]=i;
23     }
24     for(register int i=0;i<LCM;i++) {
25         for(register int j=0;j<LCM;j++) {
26             mult[i][j]=id[lcm(mul[i],mul[j])];
27         }
28     }
29 }
30 qword f[2][SUM][LCM][2];
31 inline qword calc(const qword &n) {
32     if(!n) return 1;
33     const int len=__builtin_log10(n)+1;
34     __builtin_memset(f[len&1],0,sizeof f[len&1]);
35     f[len&1][0][0][true]=1;
36     for(register int i=len;i;i--) {
37         __builtin_memset(f[!(i&1)],0,sizeof f[!(i&1)]);
38         const int cur=n%pow[i]/pow[i-1];
39         for(register int j=0;j<SUM;j++) {
40             for(register int k=0;k<LCM;k++) {
41                 if(!f[i&1][j][k][true]&&!f[i&1][j][k][false]) continue;
42                 f[!(i&1)][(((j<<2)+j)<<1)%SUM][k][false]+=f[i&1][j][k][false];
43                 f[!(i&1)][(((j<<2)+j)<<1)%SUM][k][!cur]+=f[i&1][j][k][true];
44                 for(register int p=1;p<10;p++) {
45                     f[!(i&1)][((((j<<2)+j)<<1)+p)%SUM][mult[k][p-1]][false]+=f[i&1][j][k][false];
46                     if(p<cur) f[!(i&1)][((((j<<2)+j)<<1)+p)%SUM][mult[k][p-1]][false]+=f[i&1][j][k][true];
47                     if(p==cur) f[!(i&1)][((((j<<2)+j)<<1)+p)%SUM][mult[k][p-1]][true]+=f[i&1][j][k][true];
48                 }
49             }
50         }
51     }
52     qword ret=0;
53     for(register int j=0;j<SUM;j++) {
54         for(register int k=0;k<LCM;k++) {
55             if(!(j%mul[k])) ret+=f[0][j][k][true]+f[0][j][k][false];
56         }
57     }
58     return ret;
59 }
60 int main() {
61     init();
62     for(register int T=getint();T;T--) {
63         const qword l=getint(),r=getint();
64         __builtin_printf("%I64u\n",calc(r)-calc(l-1));
65     }
66     return 0;
67 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM