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.用自己的结果算其他的结果: 以上两 ...
随机推荐
- (转载)MS SQL Server 未公开的加密函数有哪些?
MS SQL Server 未公开的加密函数有哪些? 以下的文章是对MS SQL Server 未公开的加密函数的具体操作,如果你对其相关的实际操作有兴趣的话,你就可以点击了. MS SQL Serv ...
- Spark Streaming揭秘 Day7 再探Job Scheduler
Spark Streaming揭秘 Day7 再探Job Scheduler 今天,我们对Job Scheduler再进一步深入一下,对一些更加细节的源码进行分析. Job Scheduler启动 在 ...
- Python学习_算数运算函数
记录以grades列表为例,分别定义输出.求和.平均值.方差和标准差函数,并输出相应的值 grades = [100, 100, 90, 40, 80, 100, 85, 70, 90, 65, 90 ...
- Centos6.4 安装NLTK
NLTK 安装链接 http://www.nltk.org/install.html 不知道什么原因打不开pypi 的网站 http://pypi.python.org/pypi/setuptool ...
- Android UI学习1:控件和基本事件的响应
在任何一个 GUI 系统中,控制界面上的控件(通常称为控件)都是一个基本的内容.对于 Android 应用程序,控件称为 View. 在 Android 中,在处理 UI 中的各种元素的时候,两个程序 ...
- c语言文件操作函数详解
一.文件操作注意点: 1 打开文件时,如果打开方式加“+”,表示该文件可以“写” ; 2 退出程序一般用exit函数,正常退出参数为0,非正常退出参数为正零值 ; 3 文件的读写操作:按字符.字符串. ...
- 操作邮箱的类和文件的Md5【粘】
MailMessage mailMsg = new MailMessage();//两个类,别混了,要引入System.Net这个Assembly mailMsg.From ...
- android/IOS各平台分享链接/跳转链接配置说明(备用)
Android: [Java] 纯文本查看 复制代码 ? 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 微信/朋友圈 //设置 ...
- maven插件mybatis-generator生成代码配置
鸣谢:http://my.oschina.net/u/1763011/blog/324106?fromerr=nJakGh4P (也可参看此博客进行配置) http://www.cnblogs.com ...
- unity 3d 获取鼠标当前坐标
获取当前鼠标position:Input.mousePosition;