您的位置:首页 > 其它

【SDOI2013】淘金

2015-12-05 23:12 369 查看

题目

小 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,Sumx∗SumySumx*Sumy最大值的和

1.

仔细一看,其实这道题的坐标是可以分成两部分,然后再处理的。

于是我们便可以求出y=f(x)的个数。

又因为这题的特殊性(y是又1..9之间的数相乘)

所以y是只含有2,3,5,7因子的数,

故我们可以用数位dp求出每个存在的数的出现的次数:

我们设f[i,j,k,l,t,o]为前i位,2j∗3k∗5l∗7t2^j*3^k*5^l*7^t出现的次数且2j∗3k∗5l∗7t2^j*3^k*5^l*7^t<=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]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.

[code]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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: