【SDOI2013】淘金

来源:互联网 发布:淘宝运营周计划表 编辑:程序博客网 时间:2024/04/27 18:14

题目

小 Z在玩一个 叫做《淘金者》的游戏。游戏的世界是一个 二维坐标 。X轴、Y轴坐标范围均为1..N。初始的时候,所有的整数坐标点上均有一块金子,共 N*N 块。

一阵风吹过, 金子的位置发生了一些变化。细心的小Z发现, 初始 在(i, j) 坐标 处的金子会变到 (f(i),f(j))坐标 处。其中f(x)表示 x各位数字的乘积 ,例如 ,例如 f(99)=81,f(12)=2,f(10)=0。如果金子变化后的坐标不在 1..N 的范围内,我们认为这块金子已经 被移出游戏。 同时可以发现, 对于变化之后的游戏局面, 某些 坐 标上的金子数量可能 不止一块 ,而另外一些坐标上可能已经没有金子 。这次变化 之后, 游戏将不会再对 金子的位置和数量进行改变,玩家可以开始采集工作。

小 Z很懒 ,打算 只进行 只进行 K次采集 。每次采集可以得到某 一个坐标上的所有 金子 ,采集之后该坐标上的金子数变为 0。

现在小 Z希望知道,对于变化之后的游戏局面,在采集次数为K的前提下, 最多可以采集到少块金子?

答案可能很大,小 Z希望得到1000000007 (10^ 9+7) 取模之后的答案。

题意

即让你找k个点是改变后存在的次数最多的和。

分析

我们可以发现这题求的是k个x,y,SumxSumy最大值的和
1.
仔细一看,其实这道题的坐标是可以分成两部分,然后再处理的。
于是我们便可以求出y=f(x)的个数。
又因为这题的特殊性(y是又1..9之间的数相乘)
所以y是只含有2,3,5,7因子的数,
故我们可以用数位dp求出每个存在的数的出现的次数:
我们设f[i,j,k,l,t,o]为前i位,2j3k5l7t出现的次数且2j3k5l7t<=n。
o=0,前面组成的数不等于n且小于等于n
o=1,前面组成的数等于n
那么转移便很简单了:
f[i+1,j+ch1,k+ch2,l+ch3,t+ch4,change(o)]+=f[i,j,k,l,o]
2.
我们设:
a1>a2>a3>a4>a5….atot(ai为存在的数的次数,前文的Sum)
然后我们发现答案加上的数一定是某k个ai*aj
那么现在的问题就是如何快速的算出前k个最大的ai*aj。
这时我们可以用堆处理:
首先把a1与其他的tot-1个数相乘放到堆里,且记录两个相乘的数的下标。(f[i,1]=i;f[i,2]=1;f[i,3]=a[f[i,1]]*a[f[i,2]];)
然后循环k次:取出栈首,且++f[1,2],算出新的f[1,3]=a[f[1,1]]*a[f[1,2]],再放进栈首。
为什么是对的呢?
我们可以这样想:
栈里面的x(f[i,1])不变是因为我们考虑f[i,3]为表示由x组成的没用过的最大值,而我们每次用过了y(f[i,2]),之后的次大值就是y+1.

const mo=1000000007;var    f:array[0..14,0..36,0..25,0..25,0..12,0..1] of longint;    ch,i,m,j,k,l,r,num,o,p,nu,ew:longint;    n,ans,t:int64;    an:array[1..240000] of int64;b:array[0..240000,1..3] of int64;    bit:array[0..100] of longint;    chr:array[0..9,1..4] of longint=(    (0,0,0,0),(0,0,0,0),(1,0,0,0),(0,1,0,0),(2,0,0,0),(0,0,1,0),(1,1,0,0),(0,0,0,1),(3,0,0,0),(0,2,0,0));function pd(x,y,z,k:longint):boolean;begin exit((x<37)and(y<26)and(z<26)and(k<13));end;function got(x,y,z,k:longint):integer;var i:longint;o:int64;begin o:=1;    for i:=1 to x do begin o:=o*2;if o>n then exit(1);end;    for i:=1 to y do begin o:=o*3;if o>n then exit(1);end;    for i:=1 to z do begin o:=o*5;if o>n then exit(1);end;    for i:=1 to k do begin o:=o*7;if o>n then exit(1);end;    if o=n then exit(0) else exit(-1);end;procedure qsort(l,r:longint);var i,j:longint;t,mid:int64;begin    mid:=an[(l+r)shr 1];i:=l;j:=r;    repeat        while an[i]>mid do inc(i);        while an[j]<mid do dec(j);        if i<=j then begin t:=an[i];an[i]:=an[j];an[j]:=t;inc(i);dec(j);end;    until i>j;    if l<j then qsort(l,j);    if i<r then qsort(i,r);end;procedure up(x:int64);begin    while (x>1)and(b[x,1]>b[x div 2,1]) do begin        b[0]:=b[x];b[x]:=b[x div 2];b[x div 2]:=b[0];x:=x div 2;    end;end;procedure down(x:int64);var k:int64;begin    while ((x*2<=nu)and(b[x,1]<b[x*2,1]))or((x*2+1<=nu)and(b[x,1]<b[x*2+1,1])) do begin         k:=x*2;         if (k+1<=nu)and(b[k,1]<b[k+1,1]) then k:=k+1;         b[0]:=b[x];b[x]:=b[k];b[k]:=b[0];x:=k;    end;end;begin    read(n,m);t:=n;    while t<>0 do begin inc(bit[0]);bit[bit[0]]:=t mod 10;t:=t div 10;end;    for ch:=1 to bit[bit[0]] do begin if ch=bit[bit[0]] then p:=1 else p:=0;    f[bit[0],chr[ch,1],chr[ch,2],chr[ch,3],chr[ch,4],p]:=1;end;    for i:=bit[0] downto 2 do begin        for ch:=1 to 9 do        f[i-1,chr[ch,1]+j,chr[ch,2]+k,chr[ch,3]+l,chr[ch,4]+r,0]:=f[i-1,chr[ch,1]+j,chr[ch,2]+k,chr[ch,3]+l,chr[ch,4]+r,0]+1;        for j:=0 to 36 do            for k:=0 to 25 do                for l:=0 to 25 do                    for r:=0 to 12 do                    for o:=0 to 1 do                    if f[i,j,k,l,r,o]>0 then begin                       for ch:=1 to 9 do begin                          if pd(chr[ch,1]+j,chr[ch,2]+k,chr[ch,3]+l,chr[ch,4]+r) then begin                          if (o=1)and(ch>bit[i-1]) then break;                          if (o=1)and(ch=bit[i-1]) then p:=1 else p:=0;                          f[i-1,chr[ch,1]+j,chr[ch,2]+k,chr[ch,3]+l,chr[ch,4]+r,p]:=f[i-1,chr[ch,1]+j,chr[ch,2]+k,chr[ch,3]+l,chr[ch,4]+r,p]+f[i,j,k,l,r,o];                          ew:=f[i-1,chr[ch,1]+j,chr[ch,2]+k,chr[ch,3]+l,chr[ch,4]+r,p];                          if (chr[ch,1]+j=0)and(chr[ch,2]+k=0)and(chr[ch,3]+l=0)and(chr[ch,4]+r=1)and(p=0)and(i-1=13) then                           ans:=ans;                          end;                       end;                    end;    end;    num:=0;    for i:=0 to 36 do        for j:=0 to 25 do            for k:=0 to 25 do                for l:=0 to 25 do                if (got(i,j,k,l)<1) then begin                   if (f[1,i,j,k,l,0]+f[1,i,j,k,l,1]>0) then begin                   inc(num);an[num]:=f[1,i,j,k,l,1]+f[1,i,j,k,l,0];                   end;                end;    qsort(1,num);nu:=num;    for i:=1 to num do begin    b[i,1]:=(an[i]*an[1]);b[i,2]:=an[i];b[i,3]:=1;up(i);end;    for i:=1 to m do begin        ans:=(ans+b[1,1])mod mo;        b[1,1]:=(b[1,2]*an[b[1,3]+1]);b[1,3]:=b[1,3]+1;        down(1);    end;    writeln(ans);end.
0 0