14级寒假集训————数论基础

来源:互联网 发布:网络统考成绩查询时间 编辑:程序博客网 时间:2024/06/06 13:01

题目链接:点击打开链接

A.

题目大意:
对自然数进行重新排列,排列规则如下:首先排列从1到n的奇数(升序),然后排列从1到n的偶数(升序)。输出这样排列后的第k个数。

解题思路:
首先分析,当n为偶数时,num(奇) == num(偶);当n为奇数时,num(奇) + 1 == num(偶)

接下来我们以(n + 1) / 2为分界线,把前面的num(奇)和后面的num(偶)分开。如果k小于等于(n+1) / 2,那么一定在奇数范围内,分析规律得出第k个数为k * 2 – 1;如果k大于(n+1) / 2,那么一定在偶数范围内,分析规律得出第k个数为(k – (n + 1) / 2 ) * 2。

完整代码:

#include <iostream>#include <cstdio>using namespace std;__int64 n , k;void solve(){    printf("%I64d\n" , k <= (n + 1) / 2 ? k * 2 - 1 : (k - (n + 1) / 2) * 2);}int main(){    #ifdef DoubleQ    freopen("in.txt","r",stdin);    #endif    while(~scanf("%I64d%I64d" , &n , &k))        solve();    return 0;}

B.

题目大意:
一个山丘周围有逆时针标号为0到n-1的洞,兔子躲在某个洞中。狼从标号0开始,沿逆时针方向追赶兔子。规则如下:例如m=2,n=6,狼进过洞的标号依次为0、2、4、0。如果兔子隐藏在标号为1、3、5的洞内,就不会被狼吃掉,我们称这样的洞为safe holes。
对于每组m和n,如果存在safe holes,输出YES,否则输出NO。

解题思路:
首先一定会想到如果m和n都是偶数或者m和n之间存在不为1的倍数关系,那么一定存在safe holes使得狼无法到达;
再想一想,如果gcd( m , n) == 1,那么一定不会存在safe holes,狼会找遍所有的洞,最终吃掉兔子。

完整代码:

#include <cstdio>#include <iostream>using namespace std;int gcd(int a , int b){    return b == 0 ? a : gcd(b , a % b);}void solve(){    int n , m;    scanf("%d%d",&n,&m);    printf("%s\n" , gcd(n , m) != 1 ? "YES" : "NO");}int main(){    #ifdef DoubleQ    freopen("in.txt","r",stdin);    #endif    int T;    scanf("%d",&T);    while(T--)        solve();    return 0;}

C.

题目大意:
哥德巴赫猜想说:“每个不小于4的偶数可以表示成两个素数之和。”让我们定义一个新的猜想:“每个不小于12的整数可以表示成两个合数的和。”

解题思路:
首先会想到从4到n遍历,如果i 和 n – i 都是合数,那么输出即可。
再想一想,可以用素数筛法进行打表,把100000内的素数标记为true,合数标记为false。从4到n遍历,如果pri[ i ] 和pri[ n – i ]都是合数的话,输出即可。
附上另外一种思路:如果n是偶数,那么输出4和n-4即可,因为4是最小的合数,n-4也必为偶数(n >12);如果n是奇数,那么输出9和n - 9即可,因为9是合数里最小的奇数,n - 9必为偶数。

完整代码:

朴素方法

#include <iostream>#include <cstdio>#include <cmath>using namespace std;int n;bool is(int key){    int m = sqrt(key);    for(int i = 2 ; i <= m ; i ++)        if(key % i == 0)            return true;    return false;}void solve(){    for(int i = 4 ; i <= n ; i ++)        if(is(i) && is(n - i))        {            printf("%d %d\n", i , n - i);            return;        }}int main(){    #ifdef DoubleQ    freopen("in.txt","r",stdin);    #endif    while(~scanf("%d",&n))        solve();    return 0;}

打表筛法

#include <iostream>#include <cstdio>#include <cmath>#include <cstring>using namespace std;int n;const int maxn = 1000001;bool pri[maxn];void is(){    memset(pri , true , sizeof(pri));    pri[0] = pri[1] = false;    int m = sqrt(maxn);    for(int i = 2 ; i <= m ; i ++)    {        if(pri[i])        {            for(int j = i * i ; j < maxn ; j += i)                pri[j] = false;        }    }}void solve(){    for(int i = 4 ; i <= n ; i ++)        if(!pri[i] && !pri[n - i])        {            printf("%d %d\n", i , n - i);            return;        }}int main(){    #ifdef DoubleQ    freopen("in.txt","r",stdin);    #endif    is();    while(~scanf("%d",&n))        solve();    return 0;}

另外一种解法

#include <iostream>#include <cstdio>using namespace std;int n;int main(){while(~scanf("%d", &n))    {        if(n%2==0)            printf("4 %d\n", n - 4);        else            printf("9 %d\n", n - 9);    }return 0;}



D.

题目大意:
100层的电梯,电梯显示器会显示两位数字(不满两位高位用0替代),代表当前层数。但是由于机器故障,显示器的某些灯没有亮。给你当前显示器的数字n,问它有多少种可能的层数。

解题思路:
可以把显示器的灯想象成火柴棍,对于当前数字,通过增添火柴棍,使其构成另外一个数字。设n的十位为a,个位为b。a通过增添火柴棍所能构成Pa个数字,b通过增添火柴棍所能构成Pb个火柴棍。那么Pa * Pb即为所求。
0可以构成0和8;
1可以构成1、7、3、4、8、9、0;
2可以构成2、8;
3可以构成3、9、8;
4可以构成4、9、8;
5可以构成5、6、8、9;
6可以构成6、8;
7可以构成7、3、9、0、8;
8只可以构成8;
9可以构成9、8。

完整代码:

#include <iostream>#include <cstdio>using namespace std;int n;int a[] = {2 , 7 , 2 , 3 , 3 , 4 , 2 , 5 , 1 , 2};void solve(){    printf("%d\n" , a[n % 10] * a[n / 10]);}int main(){    #ifdef DoubleQ    freopen("in.txt","r",stdin);    #endif    while(~scanf("%d",&n))        solve();    return 0;}

E.

题目大意:


解题思路:

预处理出前1000个斐波那契数,编写高精度加法函数,最后实现O(1)时间的查找。论C++和JAVA写高精度的代码量。


完整代码:

C++版

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn = 1001;string f[maxn];string add(string a , string b){    int lena = a.length();    int lenb = b.length();    int maxlen = max(lena , lenb);    int minlen = min(lena , lenb);    string maxx = lena >= lenb ? a : b;    string minn = lena < lenb ? a : b;    string result = "";    reverse(maxx.begin() , maxx.end());    reverse(minn.begin() , minn.end());    int k = 0;    int key;    for(int i = 0 ; i < minlen ; i ++)    {        key = (maxx[i] - '0') + (minn[i] - '0') + k;        if(key > 9)        {            k = key / 10;            key -= k * 10;        }        else            k = 0;        result += (char)(key + '0');    }    for(int i = minlen ; i < maxlen ; i ++)    {        key = (maxx[i] - '0') + k;        if(key > 9)        {            k = key / 10;            key -= k * 10;        }        else            k = 0;        result += (char)(key + '0');    }    if(k)        result += (char)(k + '0');    reverse(result.begin() , result.end());    return result;}void fib(){    f[1] = f[2] = "1";    for(int i = 3 ; i < maxn ; i ++)        f[i] = add(f[i-1] , f[i-2]);}void solve(){    int n;    scanf("%d",&n);    cout << f[n] << endl;}int main(){    #ifdef DoubleQ    freopen("in.txt" , "r" , stdin);    #endif;    int T;    scanf("%d",&T);    fib();    while(T--)        solve();    return 0;}

JAVA版

import java.math.*;  import java.util.Scanner;    public class Main {      public static void main(String[] args) {          Scanner cin = new Scanner(System.in);          BigInteger m[] = new BigInteger[1001];          BigInteger start = new BigInteger("1");          m[1] = start;          m[2] = start;          for(int i = 3 ; i < 1001 ; i ++){              m[i] = m[i-1].add(m[i-2]);          }             int n = cin.nextInt();          while(n != 0){              int key = cin.nextInt();              System.out.println(m[key]);              n--;          }      }  }  

F.

题目大意:
给一个长度为n的整数序列a[0],a[1],•••,a[n - 1],找出两个整数a[ i ]和a[ j ] (i < j),使得a[i] – a[j]尽量大。

解题思路:
首先会想到O(n^2)的暴力解法,很可惜这样做一定会超时,因为n达到10^5.
这道题O(n)时间内可解。对于每一个固定的j,我们应选择的是小于j且a[ i ]最大的i ,而和a[ j ]的具体值无关。我们从小到大枚举j , 顺便维护a[ i ]的最大值即可。

完整代码:

#include <cstdio>#include <iostream>#include <algorithm>using namespace std;const int maxn = 1000001;int a[maxn];void solve(){    int n;    scanf("%d",&n);    for(int i = 0 ; i < n ; i ++)        scanf("%d",&a[i]);    int maxi = a[0];    int maxx = a[0] - a[1];    for(int i = 1 ; i < n ; i ++)    {        maxi - a[i] > maxx ? maxx = maxi - a[i] : maxx = maxx;        a[i] > maxi ? maxi = a[i] : maxx = maxx;    }    printf("%d\n",maxx);}int main(){#ifdef DoubleQ    freopen("in.txt","r",stdin);#endif    int T;    scanf("%d",&T);    while(T--)        solve();    return 0;}



0 0
原创粉丝点击