zoukankan      html  css  js  c++  java
  • bzoj3131

    这是一道很好也很烦的综合题……

    首先我们肯定要先把f(i)处理出来这是毫无疑问的

    我们要求出数位乘积为now的个数,首先是空间上的问题

    直接肯定会爆空间,不难发现

    乘积的质因数只有2,3,5,7,并且指数也不是特别大

    暴力可得到不同的乘积最多只有15000不到

    然后我们就可以对其离散化然后数位dp

    dp完之后,对于点(p,q),这上面的金子个数是sum(p)*sum(q)个 (sum表示数位乘积为p的数的个数)

    然后我们要求金子前k多的点,当状态太多无法算出所有状态求最优值时,我们常常用堆来维护

    首先我们对sum排序(假定降序),对于每个乘积x,设乘积x离散化后对应的编号为w(x)

    在x行上金子最多的点一定是sum[w(x)]*sum[1],次大的点一定是sum[w(x)]*sum[2]……

    然后我们对当前这n行上最多的点维护一个大根堆

    当我们每次将堆顶的点取出时,堆顶所在行的下一大的点可能是之后选取结果产生影响,

    因此我们要将这行下一大的点加入堆,一共只要弹k次,所以复杂度为O(klogt)

      1 const maxn=200010;
      2       mo=1000000007;
      3 
      4 type arr=array[0..maxn] of int64;
      5 
      6 var a,sum,h,loc,num:arr;
      7     b:array[0..30] of int64;
      8     f:array[0..20,0..maxn] of int64;
      9     n,ans,x:int64;
     10     c,m,t,i:longint;
     11 
     12 procedure swap(var a,b:int64);
     13   var c:int64;
     14   begin
     15     c:=a;
     16     a:=b;
     17     b:=c;
     18   end;
     19 
     20 procedure sort(l,r:longint;var a:arr);
     21   var i,j:longint;x,y:int64;
     22   begin
     23     i:=l;
     24     j:=r;
     25     x:=a[(l+r) shr 1];
     26     repeat
     27       while a[i]<x do inc(i);
     28       while x<a[j] do dec(j);
     29       if i<=j then
     30       begin
     31         swap(a[i],a[j]);
     32         inc(i);
     33         dec(j);
     34       end;
     35     until i>j;
     36     if i<r then sort(i,r,a);
     37     if j>l then sort(l,j,a);
     38   end;
     39 
     40 procedure prepare;
     41   var i,j,k,l:int64;
     42   begin
     43     i:=1;
     44     while i<=n do
     45     begin
     46       j:=i;
     47       while j<=n do
     48       begin
     49         k:=j;
     50         while k<=n do
     51         begin
     52           l:=k;
     53           while l<=n do
     54           begin
     55             inc(m);
     56             a[m]:=l;
     57             l:=l*7;
     58           end;
     59           k:=k*5;
     60         end;
     61         j:=j*3;
     62       end;
     63       i:=i*2;
     64     end;
     65     sort(1,m,a);
     66   end;
     67 
     68 procedure work;
     69   begin
     70     t:=0;
     71     x:=n;
     72     while x<>0 do
     73     begin
     74       inc(t);
     75       b[t]:=x mod 10;
     76       x:=x div 10;
     77     end;
     78   end;
     79 
     80 function find(l,r:longint;x:int64):longint;
     81   var mid:longint;
     82   begin
     83     while l<r do
     84     begin
     85       mid:=(l+r)shr 1;
     86       if a[mid]=x then exit(mid);
     87       if a[mid]<x then l:=mid+1 else r:=mid-1;
     88     end;
     89     if a[l]=x then exit(l);
     90     exit(0);
     91   end;
     92 
     93 procedure count;
     94   var i,j,k:longint;
     95       now,y:int64;
     96   begin
     97     work;
     98     f[0][1]:=1;  //f[i,j]表示到第i位,乘积为j(j是离散化后的排名)的方案数
     99     for i:=1 to t-1 do
    100       for j:=1 to m do
    101         for k:=1 to 9 do
    102           if (a[j] mod k=0) then
    103             f[i,j]:=f[i,j]+f[i-1,find(1,j,a[j] div k)];
    104 
    105     now:=1;
    106     for i:=t downto 1 do
    107     begin
    108       for j:=1 to b[i]-1 do  //肯定不可能是0
    109         for k:=1 to m do
    110           if (a[k]>=now*j) and ((a[k] div now) mod j=0) and (a[k] mod now=0) then
    111             sum[k]:=sum[k]+f[i-1,find(1,k,a[k] div (now*j))];
    112       now:=now*b[i];
    113       if now=0 then break;
    114     end;
    115     if now<>0 then inc(sum[find(1,m,now)]);
    116     for i:=1 to m do
    117       for j:=1 to t-1 do
    118         sum[i]:=sum[i]+f[j,i];
    119   end;
    120 
    121 procedure sift(i,n:longint);
    122   var j:longint;
    123       x:int64;
    124   begin
    125     x:=h[i];
    126     j:=i shl 1;
    127     while j<=n do
    128     begin
    129       if (j<n) and (h[j]<h[j+1]) then inc(j);
    130       if x>=h[j] then exit
    131       else begin
    132         swap(h[i],h[j]);
    133         swap(loc[i],loc[j]);
    134         swap(num[i],num[j]);
    135         i:=j;
    136         j:=j shl 1;
    137       end;
    138     end;
    139   end;
    140 
    141 begin
    142   readln(n,c);
    143   prepare;
    144   work;
    145   count;
    146   sort(1,m,sum);  //为了统一形式,这里是升序
    147   for i:=1 to m do
    148   begin
    149     h[i]:=sum[i]*sum[m];  //当前第i行上最大的点
    150     loc[i]:=m;  
    151     num[i]:=i;  //所代表的行
    152   end;
    153   for i:=m downto 1 do
    154     sift(i,m);
    155   ans:=0;
    156   for i:=1 to c do
    157   begin
    158     ans:=(ans+(h[1] mod mo)) mod mo;
    159     dec(loc[1]);  //加入这行下一大的点
    160     h[1]:=sum[num[1]]*sum[loc[1]];
    161     sift(1,m);
    162   end;
    163   writeln(ans);
    164 end.
    View Code
  • 相关阅读:
    2021.02.09 【ABAP随笔】-Excel高效输出工具-xlsx workbench-输出多个Sheet
    2021.02.07 【ABAP随笔】-Excel高效输出工具-xlsx workbench
    Thrift did not exit cleanly
    Docker部署Springboot项目,Invalid or corrupt jarfile /app.jar
    为jenkins设置nginx作为反向代理
    Jenkins安装报错 No valid crumb was included in request
    判断当前设备是ios还是安卓
    vue 路由跳转四种方式 (带参数)
    Vue table的column属性,render函数生成switch开关和button按钮
    H5页面自定义 pxTorem 函数进行单位转换
  • 原文地址:https://www.cnblogs.com/phile/p/4473158.html
Copyright © 2011-2022 走看看