51nod 1643 小Q的家庭作业

题意:

f(n) = sigma(gcd(i,n))  1 <= i <= n

g(n) = sigma(f(d))    d | n

n = x1 * x2 * ... * xm

其中 x[i+1] = (a * x[i] + b) % c + 1

1 <= m <= 10^18

1 <= c <= 10^7

1 <= x[1],a,b  <= c

首先,发现f,g函数都是积性函数

并且推下公式:g[n] = n * (k1 + 1 ) * (k2 + 1) * ...

n = p1^k1 * p2^k2 * ....

复杂度O(c) = O(10^7)

公式很容易推,这道题主要是空间太少了,开了数组最后都只能去掉,一个数组使用多次

然后时限也很紧,1300ms,用C++11交了好几发,一直是1400ms左右,改为C++交就1062ms了,

这个要注意

还有个地方,+0LL 被我打成 +1LL,还一直没有发现,wa了好多发。。

代码:

  //File Name: nod1643.cpp
  //Author: long
  //Mail: [email protected]
  //Created Time: 2016年12月22日 星期四 17时15分27秒

#include <bits/stdc++.h>
#define LL long long
const int MAXN = 10000000 + 1;
const int N = 664579 + 1;
const int P = (int)1e9 + 7;
int fir[MAXN],prime[MAXN],num[MAXN];
LL g,m,x,a,b,c;
int tot,C;
LL qp(LL x,LL y){
    LL res = 1;
    for(;y>0;y>>=1){
        if(y & 1){
               res = res * x;
            if(res >= P)
                res %= P;
        }
        x = x * x;
        if(x >= P) x %= P;
    }
    return res;
}
void init(){
    memset(fir,-1,sizeof(fir));
    tot = 0;
    for(int i=2,j;i<MAXN;++i){
        if(fir[i] == -1){
            prime[tot++] = i;
            fir[i] = tot - 1;
        }
        for(j=0;j<tot;++j){
            if((LL)i * prime[j] >= MAXN) break;
            fir[i * prime[j]] = j;
            if(i % prime[j] == 0) break;
        }
    }
}
void cal_num(){
//    memset(prime,0,sizeof(prime));
    prime[x] = 1,num[x] = 1,fir[1] = x;
    C = x;
    g *= x;
    LL l = 0,r = 0,len = 1;
    for(LL i=2;i<=m;++i){
        x = (a * x + b) % c + 1;
        if(x > C) C = x;
//        printf("i = %d x = %lld\n",i,x);
        if(!prime[x]){
            ++num[x];
            prime[x] = i;
            fir[i] = x;
            g = g * x;
            if(g >= P) g %= P;
        }
        else{
            l = prime[x],r = i;
            len = r - l;
            break;
        }
    }
    if(r){
        int rest = (m - r + 1) % len + l - 1;
        LL dive = (m - r + 1) / len;
        LL u = 1,v = 1,w = dive % P,tmp;
        for(LL i=l,now;i<r;++i){
            now = w;
            v = fir[i];
            u = u * v;
            if(u >= P) u %= P;
            if(i <= rest){
                   ++now;
                g = g * v;
                if(g >= P) g %= P;
            }
            tmp = num[v] + now;
            if(tmp >= P) tmp -= P;
            num[v] = tmp;
        }
        g = g * qp(u,dive);
        if(g >= P) g %= P;
    }
}
void cal_sum(LL c){
    for(LL i=c,id,p,u;i>1;--i){
        if(!num[i]) continue;
        if(prime[fir[i]] == i){
            g = g * (num[i] + 1LL);
            if(g >= P) g %= P;
        }
        else{
            id = fir[i];
            p = prime[id];
            u = num[p] + num[i];
            if(u >= P) u -= P;
            num[p] = u;
            u = num[i / p] + num[i];
            if(u >= P) u -= P;
            num[i / p] = u;
        }
    }
}
void solve(){
    g = 1;
    cal_num();
    init();
    cal_sum(C);
}
int main(){
    scanf("%lld %lld %lld %lld %lld",&m,&x,&a,&b,&c);
    solve();
    printf("%lld\n",g);
    return 0;
}
时间: 2024-10-27 22:13:04

51nod 1643 小Q的家庭作业的相关文章

家长如何检查孩子的家庭作业

小学生需要老师或家长把好检查作业这—关,失去有效的检查,那么孩子的学习能力是难以提高的.家长要学会正确的检查方法,以培养孩子仔细认真.独立思考的能力.下面与大家分享一些做法:1.孩子读—.二年级时,重点检查字迹是否写端正:做完作业时发现有不正确的地方,首先不要指出具体错误之处,而是说出大体范围,如“做得不错,但这个题有些不对的地方,你再看看.”或者在有问题的地方画上—个小圆圈,让孩子自已找出不正确的地方,以改之.若孩子找出来了,就称赞孩子聪明.能干.三年级以后,重点检查孩子做题的思路,算式的列法

家庭作业——第三章

第三章家庭作业    3.69和3.70 3.69 A:long trace(tree_ptr tp)    {        long ret = 0;        while(tp != NULL)        {           ret = tp->val;           tp = tp->left;        }        return ret;    } B:作用是从根一直遍历左子树,找到第一个没有左子树的节点的值. 3.70 A:long traverse(t

关于本周家庭作业

本周家庭作业 是仿照老师给的网页图片做像素级还原. 个人认为,其中涉及到的知识点有: 1. 语义化标签的用法: 2. 表单的用法以及其属性的意义: 3. 相对定位的用法: 4. 浮动的操作: 5. 浮动的清除方式: 采用overflow不等于visible的方式 采用clear方式 使用伪类:after方式 6. 无序列表的用法: 7. 二级菜单的制作:(此处不会,只好等着老师来讲解,已查过资料,主要归结为自己太笨……) 8. display各个属性的意义及用法: 9. sprinte图片切割的

重庆OI2017 小 Q 的棋盘

小 Q 的棋盘 时间限制: 1 Sec  内存限制: 512 MB 题目描述 小Q正在设计一种棋类游戏.在小Q设计的游戏中,棋子可以放在棋盘上的格点中.某些格点之间有连线,棋子只能在有连线的格点之间移动.整个棋盘上共有V个格点,编号为0,1,2…,V-1,它们是连通的,也就是说棋子从任意格点出发,总能到达所有的格点.小Q在设计棋盘时,还保证棋子从一个格点移动到另外任一格点的路径是唯一的.小Q现在想知道,当棋子从格点0出发,移动N步最多能经过多少格点.格点可以重复经过多次,但不重复计数. 输入 第

HDU 4520 小Q系列故事——最佳裁判

Time Limit : 500/200ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other) Problem Description 过去的2012年对小Q来说是很悲催的一年,失恋了12次,每次都要郁闷1个来月. 好在小Q是个体育迷,在最痛苦的时候,他常常用观看各种体育节目来麻醉自己,比如伦敦奥运会期间,小Q就常常在周末邀上一群单身同事聚在自己的蜗居,一边畅饮啤酒,一边吹牛. 小Q最喜欢看的是跳水,主要原因也是因为这个项目有中国人参

信息安全系统设计基础家庭作业

<深入理解计算机系统>家庭作业 * 8.9 答案: 进程对 是否并发 AB 否 AC 是 AD 是 BC 是 BD 是 CD 是 * 8.10 答案: A. 调用一次,返回两次: fork B. 调用一次,从不返回: execve, longjmp C. 调用一次,返回一次或者多次: setjmp * 8.11 答案: 这个程序会输出4个“hello”输出行. 因为Fork()函数的作用是调用一次返回两次.根据条件i<2,当 i = 0 时,输出2个hello,当 i = 1 时,输出2

家庭作业汇总

家庭作业 8.21 首先可以看出不论是先打印子进程还是父进程都必须满足a在c的前面,b在c的前面这两种顺序. 但是由于无法判断子进程和父进程的并发序列,所以会有一下几种输出结果:acbc.abcc.bcac.bacc. 汇总 8.21 两星题 2′           共2′

20135206于佳心-家庭作业3.63

第三章家庭作业 选题:3.63 分值:两分 作业过程: int sum_col(int n,int A[E1(n)][E2(n)],int j) { int i; int result = 0; for(i=0;i<E1(n);i++) result += A[i][j]; return result; } 上面是原来的代码 汇编代码 movl 8(%ebp),%edx ;edx:n leal (%edx,%edx),%eax ;eax:2n leal -1(%eax),%ecx ;ecx:2n

20135223何伟钦—第六章家庭作业

第六章作业 一.家庭作业6.36(20135203&&20135223) (由于题6.36与6.35基本题型一样,只是高速缓存的数据字节不一样,我直接把6.35题目修改后作为6.36题目) 考虑下面的矩阵转置函数: typedef int array[4][4]; void transpose2(array dst,array src) { int i,j; for(i=0;i<4;i++) { for(j=0;j<4;j++) { dst[i][j]=src[j][i]; }