数论阶段性考试总结

13 篇文章 0 订阅
11 篇文章 0 订阅

前文

不得不说,这次考试真的只是运气好而已~~

自己对某些初等数论的知识还不够熟悉,也不能灵活掌握(反正肯定没有yb那位AK的好)

所以又跑过来写总结.....

更重要的是,我们的Z老师也一定会在周一让我们写总结的!~~~

整体总结:

其实考的并不是太难,每道题多思考一下就可以做出来了

尴尬的是,我在考前就只做好了AC两道题的准备,结果做完后就在不停检查,后面两道就没怎么想了

经验1:任何时候一定要谦虚!!

把自己的姿态放低,排在最后一位,这样就有无限上升的空间了。但是也不要太自卑了~~~

经验2:一定不要懈怠!!

不管是文化课还是信息学,自己都有这个缺点,容易取得成绩后懈怠,这样就不能一直稳定下去,而自己做事情的时候也要学会坚持(特别是做题,要独立思考),既然自己已经取得了优势,就想办法把它扩大,而不是拿这点东西去浪~~

经验3:一定掌握每个知识点!!

自己现在有这么好的学习资源,也有azui大佬可以帮助我,如果自己还不能学好,就是自己的问题,也就是——知识点没有吃透!!

从这次考试也可看得出来T2,绞尽脑汁就是个公式板题,可见还是要把azui的课件继续嚼啊

经验4:学会总结归纳知识点

这一点不用多说,是用自己的失败一步步铺出来的,当然,文化课同样适用

切记!!我在新学期定下的目标还没有完成,一定要重新振作起来

————————————————————————————————————————————————————————

其实上面的都是给自己看的(如果觉得烦可以自动过滤)

题解:

总共4道题

T1:

 

题目描述

给定n,m,k都是小于10001的正整数,输出给定的n个数中,其m次幂能被k整除的数的个数。

输出满足条件的数的个数。

输入

两行组成,第一行是n,m,k。

第二行是n个正整数,不超过10001.

 

输出

输出满足条件的数的个数。

样例输入

3 2 50
9 10 11

样例输出

 1

这道题就不说了,就是先来热脑的,直接用快速幂搜就行了,代码就不给了

 

T2:

题目描述

经过精灵族全力抵挡,精灵终于坚持到了联络系统的重建,于是精灵向人类求助,
大魔法师伊扎洛决定弓}用博士的最新科技来抗敌。
伊扎洛:“博士,还没好吗?”
博士:“只差一步了!只需要在正确的位置装上弹药就可以了!”
博士的最新科技是全新的炸弹,但是现在还需要一步装弹药的操作。博士的炸弹有
N!个位置可以装弹药(>.<),但是只有在正确的位置装上弹药才能启动,博士将
装弹药的位置编号为1到N!,一个位置i需要装弹药,当且仅当gcd(i, N!) ≠ 1且
N! mod i ≠ 0,现在博士不要求你求出所有装弹药位置,只需要你求出满足要求
的位置的数量就可以了。

输入

一个数N

输出

表示满足要求的位置数量,答案对mod1000000007输出

样例输入

4

样例输出

9

提示

 

【数据范围】

N <= 1000000

 

这就是我说的板子题,再加上一点小小的容斥思想,具体公式为:

n!-suma-sumb+1

其中suma表示n!以内的与n互质的数,sumb表示n!的约数个数,由于1被减了两次,要加上一次

其实就是:既然求不满足,就把总的减去满足的就是解

suma就是欧拉函数,sumb可以直接用公式求

 

至于怎么求p数组与w数组,用勒让德定理即可(有道以前的有道题用过)

推荐求n的欧拉函数用第二个,不用涉及到除法

记得取模

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
using namespace std;
#define ll long long
const int mod = 1e9 + 7;
const int MAXN = 1000003;
int n;
ll prime[MAXN] , pn , phi[MAXN];
bool vis[MAXN];
ll psum[MAXN];
void pr(){
    for( int i =2 ; i <= n ; i ++ ){
        if( vis[i] == 0 ){
            phi[i] = i - 1;
            prime[++pn] = i;
        }
        for( int j =1 ; j <= pn && 1ll * i * prime[j] <= n ; j ++ ){
            vis[i*prime[j]] = 1;
            if( i % prime[j] == 0 ){
                phi[i*prime[j]] = phi[i] * prime[j];
                break;
            }
            phi[i*prime[j]] = phi[i] * ( prime[j] - 1 );
        }
    }
}
ll qpow( ll x , ll y , ll mod ){
    ll sum = 1;
    while( y ){
        if( y % 2 ) sum = sum * x % mod;
        x = x * x % mod;
        y /= 2;
    }
    return sum;
}
int main(){
    scanf( "%d" , &n );
    pr();
    for( int i = 1 ; i <= pn ; i ++ ){
        ll k = 1;
        for( int j = 1 ; k * prime[i] <= n ; j ++ ){
            k = k * prime[i];
            psum[i] += n / k;
        }
    }
    ll sum = 1;
    for( int i = 2 ; i <= n ; i ++ ){
        sum = sum * i % mod;
    }
    ll ans = 1 , ans2 = 1;
    for( int i = 1 ; i <= pn ; i ++ ){
        ans = ans * ( qpow( prime[i] , psum[i] - 1 , mod ) * ( prime[i] - 1 ) % mod ) % mod;
        ans2 = ans2 * ( psum[i] + 1 ) % mod;
    }
    sum = sum - ans - ans2 + 1;
    while( sum < 0 ){
        sum += mod;
    }
    printf( "%lld" , sum );
    return 0;
}

 

T3:

有一个数列,满足两个性质:

  1.      数列中任意两端相邻且长度相等的部分不完全相同,比如3 6 3 6 是不合法的。
  2.      该数列是左右满足条件1的数列中字典序最小的。给出一个整数N,求数列的第N项。

输入

一个整数N

N<=101000

输出

一个数,表示数列的第N项。

样例输入

20

样例输出

   3

看起来很难,其实还是有点难度的(也是四道题中有难度的题目)

下面是来自llsw的题解:

    由于要求数列不对称,所以我们可以先构造对称的,再让它变得不对称。

    1-> 1, 2 ( 1, 1 + 1 ) -> 1, 2, 1, 3 ( 1, 2, 1, 2 + 1 ) -> 1, 2, 1, 3, 1, 2, 1, 4 ( 1, 2, 1, 3, 1, 2, 1, 3 + 1 ) -> ...

    设数列为{an},则有:

    n % 2 = 1 => an = 1

    n % 4 = 2 => an = 2

    n % 8 = 4 => an = 3

    n % 16 = 8 => an = 4

    ...

    n % ( 2 ^ x ) = 2 ^ ( x - 1 ) => an = x

    n % ( 2 ^ x ) = 2 ^ ( x - 1 ) <=> n ≡2 ^ ( x - 1 ) ( mod 2 ^ x ) <=> ( n / ( 2 ^ ( x - 1 ) ) ) ≡1 ( mod 2 )

    所以我们只需要持续取模、除法直到出现n' ≡1 ( mod 2 )的情况即可

 

 

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
using namespace std;
int a[1003] , len , ans;
char s[1003];
int sum[1003] , lena;
 
int main(){
    scanf( "%s" , s );
    len = strlen( s );
    for( int i = 0 ; i < len ; i ++ )
        a[i+1] = s[i] - '0';
    while( 1 + 1 == 2 ){
        ans ++;
        if( a[len] % 2 == 1 ){
            printf( "%d" , ans );
            return 0;
        }
        int x = 0;
        for( int i = 1 ; i <= len ; i ++ ){
            a[i] = ( a[i] + x * 10 );
            x = a[i] % 2;
            a[i] /= 2;
        }
    }
    return 0;
}

 

T4:

题目描述

给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对?

输入

一个整数

1<=N<=1000000

输出

一个整数

样例输入

4

样例输出

4

提示

 

【样例解释】

 

(2,2),(2,4),(3,3),(4,2)

 

其实是做过的,我们知道,欧拉函数就是找在n以内与n互质的数,那么我们这样思考,设有一个数是x是在y范围以内与y互质的,就一定满足:

gcd(y , x) = 1

那么,如果我们同时将n乘上一个素数,如3,则就一定有:

gcd( 3*y , 3*x ) = 3

那么只要保证y*3不大于n,那么y及其y以内的数都可以满足咯,所以最后的答案就是:

ans = \sum_{i}^{pn} phi[n/prime[i]]*2+1

其中pn为n以内质数个数,prime存的是质数。

为什么要乘2呢,因为反过来也是一种情况

为什么要加1呢?是因为我们要加上(prime[i],prime[i])这一种情况,但是其它x==y相同的不能算

可以用前缀和

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
int n ;
#define ll long long
const int MAXN = 1e7 + 3;
int prime[MAXN] , pn;
ll phi[MAXN];
bool vis[MAXN];
void pr(){
    for( int i = 2 ; i <= n ; i ++ ){
        if( !vis[i] ){
            prime[++pn] = i;
            phi[i] = i - 1;
        }
        for( int j = 1 ; j <= pn && 1ll * i * prime[j] <= n ; j ++ ){
            vis[i*prime[j]] = 1;
            if( i % prime[j] == 0 ){
                phi[i*prime[j]] = phi[i] * prime[j];
                break;
            }
            phi[i*prime[j]] = phi[i] * ( prime[j] - 1 );
        }
    }
    for( int i = 2 ; i <= n ; i ++ )
    	phi[i] = phi[i] + phi[i-1];
}
int main(){
    scanf( "%d" , &n );
    pr();
    ll ans = 0;
    for( int i = 1; i <= pn ; i ++ ){
        ans = ans + phi[n/prime[i]] * 2 + 1;
    }
    printf( "%lld" , ans );
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值