码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj2326:[HNOI2011]数学作业(分段矩阵乘法)

时间:2016-08-20 00:06:16      阅读:132      评论:0      收藏:0      [点我收藏+]

标签:

      题目大意:输入n(n<=10^18)和m,将1~n的整数连起来模m输出,比如n=13则输出12345678910111213模m的数。

      设f[i]为1~i整数连起来模m的数,i的位数为k,则有f[i]=(f[i-1]*10^k+i)mod m。可以发现f[i-1]和10^k都是会变化的,不能直接矩乘,这就尴尬了>_<。但是仔细想想(跑去问CZL),其实可以分段来矩乘,把k一样的数矩乘(1..9一样,10..99一样,100..999一样)就行了。

      orz CZL初二的时候1A,然而我却WA了好几次才AC。。。自从被模的巨大常数坑过之后就不敢多用取模了,最后全加了居然就过了,坑爹的取模T_T。

真的写的非常丑的代码如下:

技术分享
type
  poi=array[1..3,1..3]of qword;
var
  map,g,c:poi;
  f:array[1..3]of qword;
  n,p,t,tt:qword;
  i,j,k,num:longint;

procedure merge(var a,b:poi);
var
  i,j,k:longint;
begin
  fillchar(c,sizeof(c),0);
  for i:=1 to 3 do
  for j:=1 to 3 do
  for k:=1 to 3 do
  c[i,j]:=(c[i,j]+((a[i,k] mod p)*(b[k,j] mod p))mod p)mod p;
  move(c,a,sizeof(c));
end;

procedure qp(n:int64);
var
  i,j,k:longint;
begin
  if tt<>1 then
  begin
    fillchar(map,sizeof(map),0);
    fillchar(g,sizeof(g),0);
  end;
  map[1,1]:=tt*10;map[1,2]:=1;map[2,2]:=1;map[2,3]:=1;map[3,3]:=1;
  g[1,1]:=1;g[2,2]:=1;g[3,3]:=1;
  while n<>0 do
  begin
    if n and 1=1 then merge(g,map);
    merge(map,map);
    n:=n>>1;
  end;
  fillchar(c,sizeof(c),0);
  for i:=1 to 3 do
  for j:=1 to 1 do
  for k:=1 to 3 do
  c[i,j]:=(c[i,j]+(g[i,k]*f[k])mod p)mod p;
  for i:=1 to 3 do
  f[i]:=c[i,1];
end;

begin
  readln(n,p);
  f[2]:=1;f[3]:=1;g[1,1]:=1;g[2,2]:=1;g[3,3]:=1;
  map[1,2]:=1;map[2,2]:=1;map[2,3]:=1;map[3,3]:=1;
  t:=1;num:=1;
  while n>=t do
  begin
    inc(num);
    t:=t*10;
  end;
  dec(num);
  tt:=1;
  for i:=1 to num do
  begin
    if i=num then qp(n-tt+1)
    else qp(tt*10-tt);
    tt:=tt*10;
  end;
  writeln(f[1]);
end.
View Code

 

bzoj2326:[HNOI2011]数学作业(分段矩阵乘法)

标签:

原文地址:http://www.cnblogs.com/Sakits/p/5789297.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!