zoukankan      html  css  js  c++  java
  • BZOJ 3131 SDOI2013 淘金 数位dp

    原题链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3131

    题意没什么好概述的。。。。。

    首先从题目对数的每一位进行相乘的操作以及N的范围可以看出来估计和数位dp有关系。

    先考虑一维的情况。可以发现一个数的每一位相乘得到的数字质因数只有2,3,5,7,并且带有0的数字是没有贡献的,同时我们可以简单证明对于题目中的函数f(x)一定有f(x)<x,也即是说所有的f(x)都是在向1靠拢,具体到哪里取决于这个数的质因数。

    于是可以令f(i,a,b,c,d,0/1)表示当前考虑第i位(这次我从高到低实现的),已经考虑的数中有多少个的数位乘积为2^a * 3^b * 5^c * 7^d,有无限制。

    方程很好写,注意特判一下当前位数不是N的位数的时候最高位的情况,注意初始化状态是有限制的。查找答案直接暴力扫一遍就可以了。

    二维?可以发现由于这是个正方形,行列信息实际上本质是一样的,同时不难发现格子(x,y)中的金子数量最终是f(0,x的质因数分解)*f(0,y的质因数分解)。

    再一想,这是个多路归并!

    上一个优先队列,问题圆满解决。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cstdlib>
     5 #include<algorithm>
     6 #include<cmath>
     7 #include<queue>
     8 #include<set>
     9 #include<map>
    10 #include<vector>
    11 #include<cctype>
    12 using namespace std;
    13 typedef unsigned long long LL;
    14 const int mo=1000000007;
    15 
    16 LL N,K,f[15][40][27][14][14][2],A[40*27*14*14];
    17 int cnt;
    18 struct data{ int p1,p2; LL v; };
    19 struct cmp{
    20     bool operator () (data x,data y){
    21         return x.v<y.v;
    22     }
    23 };
    24 priority_queue<data,vector<data>,cmp>pq;
    25 
    26 void dev(int x,int *t)
    27 {
    28     if(!x) return;
    29     while(x!=1&&x%2==0) x/=2,t[0]++;
    30     while(x!=1&&x%3==0) x/=3,t[1]++;
    31     while(x!=1&&x%5==0) x/=5,t[2]++;
    32     while(x!=1&&x%7==0) x/=7,t[3]++;
    33 }
    34 void dp()
    35 {
    36     int up=0,n[20]={0},tt[10][4]={0}; LL tmp=N;
    37     n[up++]=tmp%10,tmp/=10;
    38     while(tmp) n[up++]=tmp%10,tmp/=10;
    39     for(int i=0;i<10;i++) dev(i,tt[i]);
    40     f[up][0][0][0][0][1]=1;
    41     for(int i=up-1;i>=0;i--)
    42     for(int x=1;x<10;x++){
    43         int *t=tt[x];
    44         for(int p1=t[0];p1<=(up-i)*3;p1++)
    45         for(int p2=t[1];p2<=(up-i)*2;p2++)
    46         for(int p3=t[2];p3<=up-i;p3++)
    47         for(int p4=t[3];p4<=up-i;p4++){
    48             f[i][p1][p2][p3][p4][0]+=f[i+1][p1-t[0]][p2-t[1]][p3-t[2]][p4-t[3]][0];
    49             if(x<n[i]) f[i][p1][p2][p3][p4][0]+=f[i+1][p1-t[0]][p2-t[1]][p3-t[2]][p4-t[3]][1];
    50             if(x==n[i]) f[i][p1][p2][p3][p4][1]+=f[i+1][p1-t[0]][p2-t[1]][p3-t[2]][p4-t[3]][1];
    51         }
    52         if(i!=up-1) f[i][t[0]][t[1]][t[2]][t[3]][0]++;
    53     }
    54 }
    55 void work()
    56 {
    57     cin>>N>>K;
    58     dp();
    59     for(int p1=0;p1<37;p1++)
    60     for(int p2=0;p2<25;p2++)
    61     for(int p3=0;p3<13;p3++)
    62     for(int p4=0;p4<13;p4++){
    63         if(f[0][p1][p2][p3][p4][0]+f[0][p1][p2][p3][p4][1])
    64             A[cnt++]=f[0][p1][p2][p3][p4][0]+f[0][p1][p2][p3][p4][1];
    65     }
    66     sort(A,A+cnt);
    67     for(int i=0;i<cnt;i++)
    68         pq.push((data){i,cnt-1,A[i]*A[cnt-1]});
    69     data t;
    70     int ans=0;
    71     for(int k=1;k<=K;k++){
    72         if(pq.empty()) break;
    73         t=pq.top(); pq.pop();
    74         ans=(ans+t.v%mo)%mo;
    75         if(t.p2) pq.push((data){t.p1,t.p2-1,A[t.p1]*A[t.p2-1]});
    76     }
    77     printf("%d
    ",ans);
    78 }
    79 int main()
    80 {
    81     work();
    82     return 0;
    83 }
  • 相关阅读:
    关于选择器
    关于定位
    jq第一讲
    js第三讲
    js第2讲
    js第一讲
    HTML第三讲的补充及HTML5新增标签和属性
    CSS第 三讲概要
    CSS第二讲概要
    CSS第一讲概要
  • 原文地址:https://www.cnblogs.com/KKKorange/p/8575758.html
Copyright © 2011-2022 走看看