1. 程式人生 > >NOI 2002 機器人M號 尤拉函式

NOI 2002 機器人M號 尤拉函式

NKOJ3804 機器人 M 號

問題描述

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 的餘數。

輸入格式

第一行是一個正整數 k(1<=k<=1000),k 是 m 的不同的 素因子個數。
以下k行,每行兩個整數, pi, ei,表示m的第i個素因子和它的指數(i = 1, 2, …, k)。
p1, p2, …, pk是不同的素數,。
所有素因子按照從小到大排列,即 p1 < p2 < …< pk。
2<=pi<10,000, 1<=ei<=1,000,000。

輸出格式

包括三行。
第一行是機器人 m 號和它的老師中,所有政客的 獨立數 之和除以 10000 的餘 數。
第二行是機器人 m 號和它的老師中,所有軍人的 獨立數 之和除以 10000 的餘 數。
第三行是機器人 m 號和它的老師中,所有學者的 獨立數 之和除以 10000 的餘 數。

樣例輸入

3
2 1
3 2
5 1

樣例輸出

8
6
75

挺不錯的一道尤拉函式複習題。

首先把題目條件翻譯一下:

給出一個數M的標準分解,現在求數M的因數當中:
(1)能被分解為奇數個奇素數相乘的數的尤拉函式值之和;
(2)能被分解為偶數個奇素數的數的尤拉函式值之和;
(3)除(1),(2)以外所有因數的尤拉函式之和(不含1)

對於(1)和(2),注意到乘上一個奇質數能使(1)(2)互相轉化,不妨用f[i][0]表示討論到第i個數時滿足(2)的答案,f[i][1]表示討論到第i個數時滿足(1)的答案。考慮兩種情況的遞推關係。

這裡要用到尤拉函式的一個性質:尤拉函式是積性函式,既當gcd(a,b)=1時,有ϕ(a)×ϕ(b)=ϕ(a×b)

根據這個容易得到遞推式:

f[i][0]=f[i1][1]×(p[i]1)+f[i1][0]
f[i][1]=f[i1][0]×(p[i]1)+f[i1][1]
(pϕ(p)=p1)

這樣前兩個問題都被解決了,考慮第三個問題。這又要用到尤拉函式的一個性質:

n=d|nϕ(d)

這樣第三個問題就可以解決了,注意不含1。

程式碼:

#include<stdio.h>
#define MAXK 1005

int K,p[MAXK],e[MAXK],f[MAXK][2],M=1;
const int mod=10000;

int ksm(int a,int b)
{
    int ans=1;
    while(b)
    {
        if(b&1)ans=ans*a%mod;
        b>>=1;a=a*a%mod;
    }
    return ans;
}

int main()
{
    int i;

    scanf("%d",&K);
    for(i=1;i<=K;i++)scanf("%d%d",&p[i],&e[i]);

    f[0][0]=1;
    if(p[1]==2)f[1][0]=1;
    else f[1][1]=p[i]-1;

    for(i=1;i<=K;i++)
    {
        if(p[i]==2)continue;
        f[i][0]=(f[i-1][1]*(p[i]-1)%mod+f[i-1][0])%mod,f[i][1]=(f[i-1][0]*(p[i]-1)%mod+f[i-1][1])%mod;
    }

    for(i=1;i<=K;i++)M=M*ksm(p[i],e[i])%mod;

    M=((M-f[K][0]-f[K][1])%mod+mod)%mod;

    printf("%d\n%d\n%d",f[K][0]-1,f[K][1],M);
}