bzoj2757
非常神的数位dp,我调了几乎一天
首先和bzoj3131类似,乘积是可以预处理出来的,注意这里乘积有一个表示的技巧
因为这里质因数只有2,3,5,7,所以我们可以表示成2^a*3^b*5^c*7^d,也就是v[a,b,c,d]这个数组
这样也非常方便进行除法,乘法的状态转移,转移和要维护的东西比较多,我就直接在程序里注释了
这里维护转移的核心思想是算每一位对编号和的贡献,乘积为0和非0分开计算
const mo=;
lim=;
q:array[..,..] of longint=((,,,),(,,,),(,,,),(,,,),(,,,),
(,,,),(,,,),(,,,),(,,,));
//~对乘积的影响
var v:array[..,..,..,..] of longint;
f,s:array[..,..] of longint;
p,r,g,h:array[..] of longint;
pp:array[..] of int64;
n,a,b,c,d,i,j,t,m,k:longint;
x,y,w:int64; procedure up(var a:longint; b:longint);
begin
a:=(a+b+mo) mod mo;
end; procedure pre;
var i,j,k,p:int64;
a,b,c,d:longint;
begin
i:=;
a:=;
while i<=lim do
begin
j:=i; b:=;
while j<=lim do
begin
k:=j; c:=;
while k<=lim do
begin
p:=k; d:=;
while p<=lim do
begin
inc(t);
v[a,b,c,d]:=t;
p:=p*;
inc(d);
end;
k:=k*;
inc(c);
end;
j:=j*;
inc(b);
end;
i:=i*;
inc(a);
end;
end; procedure work;
var a,b,c,d,i,j:longint;
begin
f[,]:=;
for i:= to do
for a:= to do for b:= to do for c:= to do for d:= to do
if (v[a,b,c,d]>) and (f[i-,v[a,b,c,d]]>) then
begin
for j:= to do
begin
up(f[i,v[a+q[j,],b+q[j,],c+q[j,],d+q[j,]]],f[i-,v[a,b,c,d]]);
//f[i,S]表示i位数乘积为S的数的个数
up(s[i,v[a+q[j,],b+q[j,],c+q[j,],d+q[j,]]],s[i-,v[a,b,c,d]]+int64(f[i-,v[a,b,c,d]])*int64(j)*int64(p[i]) mod mo);
//s[i,S]表示i位数乘积为S的数的和,转移就是算当前第i位对和的贡献,显然是j(第i位的数)*p[i](位权)*f[i-,S/j]
end;
end
else if v[a,b,c,d]= then break;
h[]:=;
for i:= to do
begin
h[i]:=h[i-]* mod mo; //i位数不含0的个数
g[i]:=(g[i-]*+*int64(p[i])*int64(h[i-]) mod mo) mod mo; //i位数不含0的数的和,=+..+
end;
end; procedure get(x:int64);
begin
m:=;
while x> do
begin
inc(m);
r[m]:=x mod ;
x:=x div ;
end;
end; function can(x:int64):boolean;
begin
a:=; b:=; c:=; d:=; //拆分成2^a*^b*^c*^d
while x mod = do
begin
inc(a);
x:=x div ;
end;
while x mod = do
begin
inc(b);
x:=x div ;
end;
while x mod = do
begin
inc(c);
x:=x div ;
end;
while x mod = do
begin
inc(d);
x:=x div ;
end;
if x= then exit(true) else exit(false);
end; function sum(a:int64):longint; //防止爆int64的计算
var b:int64;
begin
b:=a-;
if a mod = then a:=a div
else b:=b div ;
a:=a mod mo;
b:=b mod mo;
exit(a*b mod mo);
end; function count(x,k:int64):longint;
var i,j,pre,a1,b1,c1,d1,ans:longint;
now:int64;
begin
if not can(k) then exit(); //k不存在
get(x);
ans:=;
for i:= to m- do //统计1~m-位数乘积为k数的和
up(ans,s[i,v[a,b,c,d]]);
now:=;
pre:=; //pre=∑(r[i]*p[i])
for i:=m downto do
begin
now:=now*int64(r[i]);
if r[i]= then break; //显然
for j:= to r[i]- do
begin
a1:=a-q[j,]; b1:=b-q[j,]; c1:=c-q[j,]; d1:=d-q[j,];
if (a1<) or (b1<) or (c1<) or (d1<) then continue;
up(ans,s[i-,v[a1,b1,c1,d1]]+int64(pre+j*p[i])*int64(f[i-,v[a1,b1,c1,d1]]) mod mo);
//和与处理的转移类似
end;
a:=a-q[r[i],]; b:=b-q[r[i],]; c:=c-q[r[i],]; d:=d-q[r[i],];
up(pre,r[i]*p[i] mod mo);
if (a<) or (b<) or (c<) or (d<) then break;
end;
if now=k then up(ans,x mod mo); //判断x
exit(ans);
end; function calc(x:int64):longint; //乘积为0的转移要复杂,容易出错
var i,j,pre,ans,e:longint;
begin
get(x);
ans:=sum(p[m]) mod mo; //先求1~m-乘积为0的数和,我们可以用补集的思想,总和-不含0的数和
for i:= to m- do
up(ans,-g[i]);
pre:=;
for i:=m downto do
begin
if r[i]= then
begin
up(ans,int64(pre)*int64(x mod pp[i] mod mo+) mod mo+sum(x mod pp[i]+));
//当前为0,后面对答案的贡献可以直接算出来
break;
end;
if i<m then up(ans,int64(pre)*int64(p[i]) mod mo+sum(pp[i]));
//否则m位数且小于等于x的数当前位可以是0,计算贡献
if i= then e:=r[i] else e:=r[i]-;
for j:= to e do
up(ans,sum(pp[i])-g[i-]+int64(pre+j*p[i])*int64((p[i]-h[i-]+mo) mod mo) mod mo);
//这里还是运用到补集的思想,和之前算乘积不为0类似
up(pre,r[i]*p[i] mod mo);
end;
exit(ans);
end; begin
readln(n);
p[]:=;
pp[]:=;
for i:= to do
begin
p[i]:=p[i-]* mod mo; //位权
pp[i]:=pp[i-]*;
end;
pre;
work;
for i:= to n do
begin
readln(x,y,w);
if w= then writeln((calc(y)-calc(x-)+mo) mod mo)
else writeln((count(y,w)-count(x-,w)+mo) mod mo);
end;
end.
bzoj2757的更多相关文章
- BZOJ2757 : [SCOI2012]Blinker的仰慕者
BZOJ AC900题纪念~~ 若K>0,则 设f[i][j]表示i位数字,积为j的数字的个数 g[i][j]表示i位数字,积为j的数字的和 DP+Hash预处理 查询时枚举LCP然后统计贡献 ...
- bzoj2757【scoi2012】Blinker的仰慕者
题目描述 Blinker 有非常多的仰慕者,他给每个仰慕者一个正整数编号.而且这些编号还隐藏着特殊的意义,即编号的各位数字之积表示这名仰慕者对Blinker的重要度. 现在Blinker想知道编号介于 ...
- [BZOJ3131] [Sdoi2013]淘金
[BZOJ3131] [Sdoi2013]淘金 Description 小Z在玩一个叫做<淘金者>的游戏.游戏的世界是一个二维坐标.X轴.Y轴坐标范围均为1..N.初始的时候,所有的整数坐 ...
- DP大大大大大赏
还是前置: 动态规划的三种实现方法: 递推,递归,记忆化搜索 然后还是从斐波那契数列开始引入: 两种求斐波那契数列的方法: 1.用其他位置的结果得到自己的结果: 2.用自己的结果算其他的结果: 以上两 ...
随机推荐
- 关于font awesome或Glyphicons字体图标不能正确显示的问题
此处讨论的是关于本地字体的安装和引进 实际操作经验中,某些网站模板设置的CSS, FONTS目录较深,如果按默认的路径设置,字体图标死活都不会显示. 解决办法是将FONTS目录,安装在网站根目录下 C ...
- window.print打印指定div实例代码
window.print可以打印网页,但有时候我们只希望打印特定控件或内容,怎么办呢,请看下面的例子 首先我们可以把要打印的内容放在div中,然后用下面的代码进行打印. 复制代码代码如下: <h ...
- js替换字符串的所有示例代码
js如何替换字符串中所有. /** * 替换字符串中所有 * @param obj 原字符串 * @param str1 替换规则 * @param str2 替换成什么 * @return 替换后的 ...
- css3 旋转效果加上双面显示效果
在学习Css3的过程中,我想做一个类似金字塔,菱形翻页效果,如图这种效果 如是,我自己设计了一个,不带js的旋转效果: 1>第一步我先设计了一个方块,内含一个旋转了45deg的小方块,代码如下: ...
- Oracle外部表的使用
外部表可以像其它表一样,用select语句作查询.但不能做DML操作,不能建index,不接受约束.这是因为它不是以段的形式存于数据库中,只是以数据字典构造存在,指向一个或多个操作系统文件. 外部表的 ...
- springmvc+json
1.在写我的springmvc demo时,由于要向前台返回相关信息,于是设置了@ResponseBody,但是要把对象转换成json格式,我却没有在xml文件里配置,所以报如下错误:HttpMedi ...
- Unity3d之Http通讯GET方法和POST方法
(一)GET方法 IEnumerator SendGet(string _url) { WWW getData = new WWW(_url); yield return getData; if(ge ...
- mac 如何让文件隐藏
1.首先,要确保知道目标文件或文件夹的名称,你不把这个名称正确地输入到终端中,Mac也无能为力啊... 2.打开终端,输入chflags hidden 3.在上述代码的后面加上该文件夹的路径,但是注意 ...
- poj 2262 Goldbach's Conjecture(素数筛选法)
http://poj.org/problem?id=2262 Goldbach's Conjecture Time Limit: 1000MS Memory Limit: 65536K Total ...
- SAX EntityResolver 的作用
1.1 何为 EntityResolver : 官方解释: 如果SAX应用程序叙事实现自定义处理外部实体,则必须实现此接口, 并使用setEntityResolver方法向SAX 驱动器注册一个实例. ...