JZOJ 1161.机器人M号

Description

3030年,Macsy正在火星部署一批机器人。 第1秒,他把机器人1号运到了火星,机器人1号可以制造其他的机器人。 第2秒,机器人1号造出了第一个机器人——机器人2号。 第3秒,机器人1号造出了另一个机器人——机器人3号。 之后每一秒,机器人1号都可以造出一个新的机器人。第m秒造出的机器人编号为m。我们可以称它为机器人m号,或者m号机器人。 机器人造出来后,马上开始工作。m号机器人,每m秒会休息一次。比如3号机器人,会在第6,9,12,……秒休息,而其它时间都在工作。 机器人休息时,它的记忆将会被移植到当时出生的机器人的脑中。比如6号机器人出生时,2,3号机器人正在休息,因此,6号机器人会收到第2,3号机器人的记忆副本。我们称第2,3号机器人是6号机器人的老师。 如果两个机器人没有师徒关系,且没有共同的老师,则称这两个机器人的知识是互相独立的。注意:1号机器人与其他所有机器人的知识独立(因为只有1号才会造机器人),它也不是任何机器人的老师。 一个机器人的独立数,是指所有编号比它小且与它知识互相独立的机器人的个数。比如1号机器人的独立数为0,2号机器人的独立数为1(1号机器人与它知识互相独立),6号机器人的独立数为2(1,5号机器人与它知识互相独立,2,3号机器人都是它的老师,而4号机器人与它有共同的老师——2号机器人)。 新造出来的机器人有3种不同的职业。对于编号为m的机器人,如果能把m分解成偶数个不同奇素数的积,则它是政客,例如编号15;否则,如果m本身就是奇素数或者能把m分解成奇数个不同奇素数的积,则它是军人,例如编号 3, 编号165。其它编号的机器人都是学者,例如编号2, 编号6, 编号9。 第m秒诞生的机器人m号,想知道它和它的老师中,所有政客的独立数之和,所有军人的独立数之和,以及所有学者的独立数之和。可机器人m号忙于工作没时间计算,你能够帮助它吗? 为了方便你的计算,Macsy已经帮你做了m的素因子分解。为了输出方便,只要求输出总和除以10000的余数。

Input

输入文件的第一行是一个正整数k(1<=k<=1000),k是m的不同的素因子个数。 以下k行,每行两个整数,pi, ei,表示m的第i个素因子和它的指数(i = 1, 2, …, k)。p1, p2, …, pk是不同的素数。所有素因子按照从小到大排列,即p1

Output

输出文件包括三行。 第一行是机器人m号和它的老师中,所有政客的独立数之和除以10000的余数。 第二行是机器人m号和它的老师中,所有军人的独立数之和除以10000的余数。 第三行是机器人m号和它的老师中,所有学者的独立数之和除以10000的余数。

Data Constraint

样例解释: m=2*3^2*5=90。90号机器人有10个老师,加上它自己共11个。其中政客只有15号;军人有3号和5号;学者有8个,它们的编号分别是:2,6,9,10,18,30,45,90。

Solution

我自认为这是水法。遇到质数2直接不管,其他的继续DP。
由于政客和军人分解质因数后的质因子均不相同,如果老师的任意质因子的指数>1,那么它们统统都是学者。因此我们只用枚举选哪些质数。
设F[0,i]表示当前从P[1]~P[i]中选出偶数个质数的乘积的独立值之和
F[1,i]………………………………………….奇……………………………………………………. (看你们能够理解吧,我有一点偷懒,呵呵)
显然当前状态是从上一个状态转移过来的,所以F[0,i]=F[0,i-1]+(^@&#^&)
我们设从P[1]~P[i-1]中选出奇数个质数的乘积为N,所以F[1,i-1]=Σφ(n)
那么现在选择的质数的乘积就为N*P[i].
我们知道φ(n* P[i])= φ(n) * φ(P[i]),φ(P[i])=P[i]-1,且N和P[i]互质,所以F[0,i]=F[0,i-1]+Σφ(n) *Σφ(P[i])=F[0,i-1]+(P[i]-1) *F[1,i-1]
关于奇数个质因子这一方面,还有这样一种可能:我可能P[1]~P[i-1]中的素数一个都不选,却偏偏选P[i]。所以F[1,i]=F[1,i-1]+(P[i]-1) *(F[0,i-1]+1)。
答案分别是F[0,k],F[1,k],M-F[0,k]-F[1,k]-1(记得取模)

Code

const mo=10000;
var f:array[0..1,0..1001] of longint;
    ii,i,j,k,l,n,m,t,x,y:longint;
    ans:int64;
    p,e:array[0..1001] of longint;
function ksm(x,y:int64):int64;
var s,t:int64;
begin
    s:=1;
    t:=x;
    while y>0 do
    begin
        if odd(y) then s:=(s*(t mod mo))mod mo;
        t:=(t*t)mod mo;
        y:=y div 2;
    end;
    exit(s mod mo);
end;
begin
    readln(k);
    ans:=1;
    for i:=1 to k do
    begin
        readln(x,y);
        if x<>2 then
        begin
            inc(ii);
            p[ii]:=x;
            e[ii]:=y;
        end;
        ans:=(ans*ksm(x,y))mod mo;
    end;
    for i:=1 to ii do
    begin
        f[0,i]:=((f[1,i-1]*(p[i]-1))mod mo+f[0,i-1])mod mo;
        f[1,i]:=((((1+f[0,i-1])mod mo)*(p[i]-1)mod mo)+f[1,i-1])mod mo;
    end;
    writeln(f[0,ii]);
    writeln(f[1,ii]);
    writeln((ans-f[0,ii]-f[1,ii]-1+100000)mod mo);
end.

当然,P和E我们可以不用数组存,我们可以在线做(这样可以省一点空间),像这样:

const mo=10000;
var f:array[0..1,0..1001] of longint;
    ii,i,j,k,l,n,m,t,x,y:longint;
    ans:int64;
function ksm(x,y:int64):int64;
var s,t:int64;
begin
    s:=1;
    t:=x;
    while y>0 do
    begin
        if odd(y) then s:=(s*(t mod mo))mod mo;
        t:=(t*t)mod mo;
        y:=y div 2;
    end;
    exit(s mod mo);
end;
begin
    readln(k);
    ans:=1;
    for i:=1 to k do
    begin
        readln(x,y);
        ans:=(ans*ksm(x,y))mod mo;
        if x<>2 then
        begin
            f[0,i]:=((f[1,i-1]*(x-1))mod mo+f[0,i-1])mod mo;
            f[1,i]:=((((1+f[0,i-1])mod mo)*(x-1)mod mo)+f[1,i-1])mod mo;
        end;
    end;
    writeln(f[0,k]);
    writeln(f[1,k]);
    writeln((ans-f[0,k]-f[1,k]-1+100000)mod mo);
end.

——2016.2.18 By Wzy

你可能感兴趣的:(Pascal程序)