标签:
题目大意:输入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.
bzoj2326:[HNOI2011]数学作业(分段矩阵乘法)
标签:
原文地址:http://www.cnblogs.com/Sakits/p/5789297.html