[Noi2002]Robot 欧拉函数+递推
2017-08-27 14:10
363 查看
题目链接:bzoj1408
—————————————-
给定一个数n,将它所有约数分为三类:
能分解成偶数个不同奇质数的乘积.(质因数的指数小于等于1)
能分解成奇数个不同奇质数的乘积.(质因数的指数小于等于1)
不满足1、2的约数.
注:1不算任何数的约数.
例如:对于正整数90:
一类约数:15.
二类约数:3、5.
三类约数:2、6、9、10、18、30、45、90.
现在告诉你正整数n,让你求得其一类约数的欧拉函数之和,二类约数的欧拉函数之和,三类约数的欧拉函数之和。结果均对10000取模。
我们将n质因数分解:n=∏i=1kpeii.
题目将给出k,以及n所有的质因数pi和其指数ei.
—————————————-
由于正整数n的欧拉函数有这么一条性质:n=∑d|nφ(d).
(不清楚的可以参考我之前的博客:常见函数讲解1:欧拉函数,其中“扩展性质”中给出了上式的证明)
所以,我们设三类约数的欧拉函数之和分别为Ans1、Ans2、Ans3,那么显然有:Ans1+Ans2+Ans3=n−1.
也就是说,假如我们求得了Ans1、Ans2,那Ans3自然能得知了。
那么我们如何求得Ans1和Ans2呢?
我们发现,对于一个一类约数a=∏mi=1pi,其中m为偶数,我们对a乘一个不属于{p1~pm}的质因数pm+1,那么我们就能把一类约数a变成二类约数a×pm+1.
我们顺着这个思路想,我们用前i−1个质因数构成的一类约数,只要乘上pi那么就能把他们全都变成二类约数了。
设s1i为前i个质因数构成的一类约数的欧拉函数之和,s2i为前i个质因数构成的二类约数的欧拉函数之和。由上面得到的结论,我们可以推出s1与s2之间存在如下的递推关系:s1i=s2i−1×φ(pi).s2i=s1i−1×φ(pi)+φ(pi).
很明显,Ans1=s1k, Ans2=s2k。所以我们只要初始化s10=s20=0,然后O(n)的递推即可得到Ans1和Ans2的值。
至于Ans3嘛,之前得出了Ans3=n−1−Ans1−Ans2这样的结论,直接计算即可。别忘了取模。
—————————————-
—————————————-
—————————————-
——wrote by miraclejzd.
—————————————-
概述
题目的意思比较复杂,大致如下:给定一个数n,将它所有约数分为三类:
能分解成偶数个不同奇质数的乘积.(质因数的指数小于等于1)
能分解成奇数个不同奇质数的乘积.(质因数的指数小于等于1)
不满足1、2的约数.
注:1不算任何数的约数.
例如:对于正整数90:
一类约数:15.
二类约数:3、5.
三类约数:2、6、9、10、18、30、45、90.
现在告诉你正整数n,让你求得其一类约数的欧拉函数之和,二类约数的欧拉函数之和,三类约数的欧拉函数之和。结果均对10000取模。
我们将n质因数分解:n=∏i=1kpeii.
题目将给出k,以及n所有的质因数pi和其指数ei.
—————————————-
题解
我们发现,上面三类约数的并集很显然就是n的所有约数(不包括1)由于正整数n的欧拉函数有这么一条性质:n=∑d|nφ(d).
(不清楚的可以参考我之前的博客:常见函数讲解1:欧拉函数,其中“扩展性质”中给出了上式的证明)
所以,我们设三类约数的欧拉函数之和分别为Ans1、Ans2、Ans3,那么显然有:Ans1+Ans2+Ans3=n−1.
也就是说,假如我们求得了Ans1、Ans2,那Ans3自然能得知了。
那么我们如何求得Ans1和Ans2呢?
我们发现,对于一个一类约数a=∏mi=1pi,其中m为偶数,我们对a乘一个不属于{p1~pm}的质因数pm+1,那么我们就能把一类约数a变成二类约数a×pm+1.
我们顺着这个思路想,我们用前i−1个质因数构成的一类约数,只要乘上pi那么就能把他们全都变成二类约数了。
设s1i为前i个质因数构成的一类约数的欧拉函数之和,s2i为前i个质因数构成的二类约数的欧拉函数之和。由上面得到的结论,我们可以推出s1与s2之间存在如下的递推关系:s1i=s2i−1×φ(pi).s2i=s1i−1×φ(pi)+φ(pi).
很明显,Ans1=s1k, Ans2=s2k。所以我们只要初始化s10=s20=0,然后O(n)的递推即可得到Ans1和Ans2的值。
至于Ans3嘛,之前得出了Ans3=n−1−Ans1−Ans2这样的结论,直接计算即可。别忘了取模。
—————————————-
代码
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> #include<ctime> #define ll long long #define For(i,j,k) for(register int i=j; i<=(int)k; ++i) #define Forr(i,j,k) for(register int i=j; i>=(int)k; --i) #define INF 0x3f3f3f3f using namespace std; const int mo = 10000; const int maxn = 1000+5; int n, x, Ans1, Ans2, Ans3; int p[maxn], e[maxn]; inline int ksm(int x, int y){ int back = 1; x %= mo; while(y){ if(y & 1) back = back*x%mo; x = x*x%mo; y >>= 1; } return back; } int main(){ scanf("%d", &n); For(i, 1, n) scanf("%d%d", &p[i], &e[i]); int s1, s2; For(i, 1, n){ if(p[i] == 2) continue; s1 = (Ans1 + Ans2*(p[i]-1)%mo)%mo; s2 = ((Ans2+p[i]-1)%mo + Ans1*(p[i]-1)%mo)%mo; Ans1 = s1, Ans2 = s2;//递推求得Ans1和Ans2. } x = 1; For(i, 1, n) x = x*ksm(p[i], e[i])%mo;//计算n在模10000意义下的值. Ans3 = (x-Ans1-Ans2-1)%mo;//计算Ans3. while(Ans3 < 0) Ans3 += mo;//防止Ans3爆负. printf("%d\n%d\n%d", Ans1, Ans2, Ans3); return 0; }
—————————————-
小结
本题的关键在于找到那个递推式计算Ans1和Ans2,结合欧拉函数的性质就能快速计算Ans3。作者想了1h小时无果,膜拜大佬之后便有了灵感。果然,分析性质这儿技能还需要多锻炼才能提高。—————————————-
——wrote by miraclejzd.
相关文章推荐
- 1408: [Noi2002]Robot|快速幂|欧拉函数
- bzoj 1408: [Noi2002]Robot (DP+欧拉函数)
- 1408: [Noi2002]Robot 欧拉函数+快速幂
- bzoj 1408 [Noi2002]Robot(欧拉函数)
- BZOJ 1408 NOI2002 Robot 数论
- 【BZOJ 1408】【NOI 2002】Robot
- 解题报告 noi 2002 robot
- NOI 2002 机器人M号 欧拉函数
- bzoj1408: [Noi2002]Robot
- BZOJ_1408_[Noi2002]Robot_数学
- BZOJ 1408: [Noi2002]Robot
- 【bzoj1408】 Noi2002—Robot
- BZOJ 1408: [Noi2002]Robot
- [BZOJ1408][Noi2002]Robot(数论+dp)
- bzoj 1408: [Noi2002]Robot(数论+DP)
- 拓展欧几里得 [Noi2002]Savage
- 【CodeVS1540】【Vijos1443】【NOI2002】银河英雄传说
- bzoj 1407: [Noi2002]Savage
- 欧拉函数的递推形式
- Codevs 1074 [NOI 2002]食物链