您的位置:首页 > 其它

NOIPの模拟_2016_7_19_t1_腐败

2016-07-19 21:14 323 查看

题目



input

第一行一个正整数n,表示序列长度

第二行n个正整数,为给出的序列A

Sample Input

3

6 4 12

Output

一个非负整数,为答案。

Sample Output

13824

Data Constraint

50%:n<=3000;

100%:n<=30000,A[i]<=10^7

题目の大意

这题并不需要2333(+10086);

我比赛时の想法与吐槽

看到题先发动技能:奥义*蒙逼!蒙逼几分钟之后愉悦的想到了分解质因数,然后就愉悦的开始打了,打到一半发现这个模数十分神奇,似乎会爆int64!?于是有好的与同学交流了一番,回忆起了以前忘记的快速乘(其实我怎么看也都不快啊)。但是因为我比较垃圾,打的代码也十分捞,十分难调,两个小错误调到了下午四点555。

大概思路

当前我们正在处理一个数x,那么我们先把ta分解成∏zs=1pkss的形式,然后把每一个小于sqrt(107)的数(也就是小于3162)放到一个f[i,j]中,f[i,j]表示在现在已经处理过的数中因子i的个数为j的个数,若有一个质数大于3162,容易发现这个质数在每一个数中指数最大为1,所以我们用一个g[i]来分开存储,这样就解决了空间的问题,然后我们分情况讨论:

设x的质因子p有tt个,分两个部分计算答案

1:f[p,1—>tt],对于这一部分我们给答案*f[p,q]*l(l为pq)

2: f[p,tt+1—>cc[p]],对于这一部分答案*f[p,q]*l(l为ptt,设cc[p]=z,则cc[p]表示不大于107的最大的pz)

对于p<3162和p>3162当然是要分开处理的啦

快速乘

设cy=107,我们现在要求a*b的积。

设a1=a mod cy;

a2=a div cy;

b1=b mod cy;

b2=b div cy;

那么a*b=(a2*cy+a1)*(b2*cy+b1),然后把ta拆开,把四项的答案都算出来然后相加就可以了,在计算的过程每做一步就mod一次就不会runtime error 了

贴代码(好长啊,还有好多调试时候的注释懒得删了2333~~)

CONST md=100000000009;cy=10000000;
VAR
T:ARRAY[0..10005,0..100]OF LONGINT;
A:ARRAY[0..30005]OF LONGINT;
B:ARRAY[0..10000005]OF LONGINT;
Q,CC:ARRAY[0..10005]OF LONGINT;
PP:ARRAY[0..1005,0..20005]OF int64;
I,J,K,L,N,x,tt,ss:LONGINT;
ANS,aa:INT64;
procedure make_Prime_Number;
var
i,j:longint;
k:int64;
bz:array[0..10005]of boolean;
begin
fillchar(bz,sizeof(bz),false);
for i:=2 to 3500 do
if bz[i]=false then
begin
j:=i+i;
while j<3500 do
begin
bz[j]:=true;
inc(j,i);
end;
end;
for i:=2 to 3162 do
if bz[i]=false then
begin
inc(q[0]);
q[q[0]]:=i;
k:=i;
j:=0;
while k<30000*3162 do
begin
inc(j);
k:=k*i;
end;
cc[i]:=j;
end;
end;
PROCEDURE MAKE_PP;
BEGIN
FOR I:=2 TO 1000 DO
BEGIN
PP[I,1]:=I;
FOR J:=2 TO 20000 DO PP[I,J]:=(PP[I,J-1]*I) MOD MD;
END;
END;
function fate(x,y:int64):int64;
var
a1,a2,b1,b2,ls:int64;
begin
a1:=x mod cy;
a2:=x div cy;
b1:=y mod cy;
b2:=y div cy;
ls:=(((((a2*b2) mod md)*cy) mod md)*cy) mod md;
ls:=ls+(((a2*b1) mod md)*cy) mod md;
ls:=ls+(((a1*b2) mod md)*cy) mod md;
ls:=(ls+a1*b1) mod md;
exit(ls);
// exit((x*y) mod md);
end;
BEGIN
//assign(input,'1.in'); reset(input);
READLN(N);
FOR I:=1 TO N DO READ(A[I]);
READLN;
ANS:=A[1];
FOR I:=2 TO N DO ANS:=fate(ANS,A[I]);
MAKE_Prime_Number;
MAKE_PP;
aa:=(cy*cy) mod md;
for i:=1 to n do
begin
x:=a[i];
j:=1;
while (q[j]<x) and (j<q[0]) do
begin
tt:=0;
while x mod q[j]=0 do
begin
inc(tt);
x:=x div q[j];
end;
if tt>0 then
begin
l:=1;
for k:=1 to tt do
begin
l:=(l*q[j]) mod md;
if t[q[j],k]>0 then
begin
if l<=1000 then ans:=fate(ans,pp[l,t[q[j],k]]) else
for ss:=1 to t[q[j],k] do ans:=fate(ans,l);
end;
end;
for k:=tt+1 to cc[q[j]] do
if t[q[j],k]>0 then
begin
if l<=1000 then ans:=fate(ans,pp[l,t[q[j],k]]) else
for ss:=1 to t[q[j],k] do ans:=fate(ans,l);
end;
inc(t[q[j],tt]);
end;
inc(j);
if sqrt(x)<q[j] then
begin
if x<3162 then
begin
if x=1 then continue;
l:=x;
if t[x,1]>0 then
if l<=1000 then ans:=fate(ans,pp[l,t[x,1]]) else
for ss:=1 to t[x,1] do ans:=fate(ans,l);
inc(t[x,1]);
for k:=2 to cc[x] do
if t[x,k]>0 then
begin
if l<=1000 then ans:=fate(ans,pp[l,t[x,k]]) else
for ss:=1 to t[x,k] do ans:=fate(ans,l);
end;
end;
break;
end;
end;
if x>3162 then
begin
for ss:=1 to b[x] do
ans:=fate(ans,x);
inc(b[x]);
end;
end;
writeln(ans);
// close(input);
END.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: