【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.
相关文章推荐
- 多媒体开发之rtmp---rtmp client 编译
- 判断一个字符串里是否含有某段字符?怎么截取一段字符?
- 10018---jQuery--遍历
- 解一元二次方程
- java.io.Serializable接口
- Brackets安装Emmet插件显示“Internal error”解决办法
- 开始学习Python,设置环境和编译一个简单的程序
- 规定时间内,生产随机数不变rand()
- 程序闪退情景一
- 恒拓开源笔试题
- 入门训练 Fibonacci数列
- 贪吃蛇
- windows下程序的命名习惯和Linux下程序的命名习惯对比
- 一个正则表达式分析(python)
- eclipse 快捷键
- 趣味C语言
- 0004.熟悉hive创建mysql数据库中的表关系
- 61,对象作为返回值
- 每天一个命令
- JUnit4参数的使用