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.用自己的结果算其他的结果: 以上两 ...
随机推荐
- Objective-C中class、Category、Block的介绍
@class 当定义一个类,必须为编译器提供两组消息,第一组(接口部分.h):构建类的实例的一个基本蓝图.必须指定类名,类的超类,类的实例变量和类型的列表,最后是类的方法的声明.第二组(实现部分.m) ...
- String类源码分析(JDK1.7)
以下学习根据JDK1.7String类源代码做注释 public final class String implements java.io.Serializable, Comparable<S ...
- log4net 配置
1.在项目中引入log4net.dll组件: 2.在App.congfig中做如下修改 在加入如下内容: 这个节点最好放在<configuration>下的第一个位置,不然在服务里会报错. ...
- EXTJS 4.2 资料 将store 传到后台
var lstAddRecord = new Array(); store.each(function (record) { lstAddRecord.push(record.data); }); E ...
- XSS前端防火墙
前一段时间,在EtherDream大神的博客里看到关于XSS防火墙的一系列文章,觉得很有意思.刚好科创要做一个防火墙,就把XSS前端防火墙作为一个创新点,着手去实现了. 在实现过程中,由于各种原因,比 ...
- 三年PS经验
- Android支付接入(四):联通VAC计费
原地址:http://blog.csdn.net/simdanfeg/article/details/9012031 注意事项: 1.联通支付是不需要自己标识软硬计费点的,当平台申请计费点的时候会提交 ...
- 我的vim配置
之前都在虚拟机下面捣鼓Linux,有种隔靴搔痒的感觉.为了更快地熟悉Linux系统,重新安装了Ubuntu,首先就是配置vim. 下面是我的vim配置,为了方便,我在代码后添加注释说明. 1.配置C/ ...
- hdu 2028 Lowest Common Multiple Plus(最小公倍数)
Lowest Common Multiple Plus Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (J ...
- mysql查看数据库命令
mysql查看数据库命令 打开的数据库的命令 mysql> use mysql Database changed 查看数据库的命令 mysql> show databases; 查看数据表 ...