机器人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

分析

先分析题意,不要被题目给绕晕,首先“一个数的知识独立的个数”指的是与m互质的数的个数。其次“x是某某的老师”其实指的是x是某某的约数。所以这样这题的题意我们就可以初步了解清楚了。
然后这样我们要求的就是那些分别是m的约数的且满足题目中条件的欧拉函数。
所以对此我们设dp方程:
f[i,j]=f[i,j]+f[i-1,j]+f[i-1,j-1]*(p[i]-1)
然后再根据题目条件分类即可。
然后还有一点,也是这题最关键的问题:如何求学者的独立数之和?
首先我们只用知道所有m的约数的欧拉函数的和是多少即可,其实也就是m!
如何证明呢?这里给出一种方法:
我们设当前i-1个质数组成的约数的个数为ansi-1
那么分类讨论:ansi
1.单独选pi,那么就是
(p1)+(p1)p+(p1)p2+(p1)p3..(p1)ppe1
2.不选pi,那么就是ansi-1
3.前面的数与pi组合:
ans(p1)+ans(p1)p+ans(p1)p2+ans(p1)p3..ans(p1)ppe1

所以ans可以推出 (ans+1)(p1)(p+..+pe1)
然后我们再用等比数列求和公式便可以得到ans->(ans+1)*(p^{e+1}-p)
由上一次代入后,ans便可以推出 ansi=p1e1..piei
这样便可以得出m的所有的约数的欧拉函数之和为m了。
到此便很好解决了问题了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cstring>
using namespace std;
const int N=1005;
const int mo=10000;
int n,p[N],e[N],f[N],ans,fir,sec;
int msort(int x,int y){
    int d=1,c=x;
    while (y){
        if (y&1) d=(d*c)%mo;
        c=(c*c)%mo;
        y=y>>1;
    }
    return d;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d %d\n",&p[i],&e[i]);
    f[0]=1;int a=1;
    if (p[1]==2) a=2;
    for(int i=a;i<=n;i++)
       for(int j=i-a+1;j;j--)
          f[j]=(f[j]+f[j-1]*(p[i]-1))%mo;
    for(int i=1;i<=n;i++) if (i%2) fir=(fir+f[i])%mo;else sec=(sec+f[i])%mo;
    ans=1;
    for(int i=1;i<=n;i++) ans=(ans*msort(p[i],e[i]))%mo;
    printf("%d\n%d\n%d\n",sec,fir,(ans-fir-sec-1+mo+mo)%mo);
    fclose(stdin);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值