8.18集训笔记

上午递归,文件

点击查看代码
#include<bits/stdc++.h>
using namespace std;
//#define T long long
typedef long long LL; // 取别名,以后使用 LL 就是 long long
const int N=5e3+10;
LL fib[N];
LL f(int n){  // 递归
    if(n<=2) return 1;
    return f(n-1) + f(n-2);
}
int main(){
    fib[0]=fib[1]=1;  // 递推
    for(int i=2; i<N; i++) {
        fib[i] = fib[i-1] + fib[i-2];
//        cout<<i<<" : "<< fib[i]<<endl;
    }
    int n;cin>>n;
//    cout<<f(n)<<endl;
    cout<<fib[n]<<endl;
    return 0;
}
  • 汉诺塔
    【例】Hanoi(汉诺)塔问题。
    古代有一个梵塔,塔内有3个座A,B,C。开始时A座上有64个盘子,盘子大小不等,大的在下,小的在上。有一个老和尚想把这64个盘子从A座移到C座,但规定每次只允许移动一个盘,且在移动过程中在3个座上都始终保持大盘在下,小盘在上。在移动过程中可以利用B座。要求编程序输出移动盘子的步骤。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=110;
void hanoi(int n,char a,char b,char c){
    if(n==1){
        // printf("%c->%c\n",a,c);
        cout<<a<<" "<<c<<endl;
        return;
    }
    hanoi(n-1, a,c,b);
    hanoi(1, a,b,c);
    hanoi(n-1, b,a,c);
}
int main(){
    int n;  cin>>n; // scanf("%d", &n);
    hanoi(n,'A','B','C');
    return 0;
}
点击查看代码
#include<iostream>
using namespace std;
const int N=1e6+10, INF=0x3f3f3f3f;
typedef long long LL;

int p;
LL halfpow(int a,int n){
    if(n==1) return a;
    LL ans = halfpow(a, n/2);
    ans = ans*ans%p;
    if(n&1) ans=ans*a%p;
    return ans;
}
int main(){
    int a,b; scanf("%d%d%d",&a,&b,&p);
    LL s = halfpow(a, b);
    printf("%d^%d mod %d=%lld\n",a,b,p,s);
    return 0;
}

文件重定向

这个其实主要对于数据测试和竞赛中有用,平常用不上,但是比赛又必须要使用

#include<iostream>
#include<cstdio>
using namespace std;
int main() {
    //替代我们的手动输入,将文件中内容读入输入流中
    freopen("输入文件名", "r", stdin);

    //将输出流中的数据写入文件中
    freopen("输出文件名", "w", stdout);

    //正常的执行程序
    long long a,b; cin>>a>>b;
    cout<<a+b<<endl;

    fclose(stdin);  //关闭输入流
    fclose(stdout); //关闭输出流
    return 0;
}

在 windows 系统上可以不写fclose,系统会自动关闭,
但是 Linux 系统上如果不写会出现问题,无法正常关闭或文件保存出现问题,OI系列评测均是在Linux系统上进行的,所以一定要手动关闭。

其实用这个来代替我们的手动输入是比较方便的,大家可以多习惯这样的用法。

举例:【题目描述】输入a,b, 输出a+b的结果(\(0<=a, b<=2^31\))。

题目 a+b
提交源文件名 ab.cpp
输入文件名 ab.in
输出文件名 ab.out

最后应该提交的的源文件,应当命名为:ab.cpp(注意大小写),并存放如下内容

#include<iostream>
#include<cstdio>
using namespace std;
int main() {
    freopen("ab.in", "r", stdin);   //从文件 ab.in 中读入信息
    freopen("ab.out", "w", stdout); //将输出信息保存至文件 ab.out

    long long a,b; cin>>a>>b;
    cout<<a+b;

    fclose(stdin);  //关闭输入流
    fclose(stdout); //关闭输出流
    return 0;
}

这样程序就会从文件 ab.in 里面读取前两个数据,分别赋值给a,b,从而替代我们手动输入的过程。
并且会将a+b的结果保存到文件 ab.out 里面,就不会在控制台窗口输出(也就是小黑方框)。

另外注意,OI(CSP/NOIP/..)系列的比赛中源文件提交有格式要求,注意官网信息,这里大概说明几点:

  1. 源程序命名,严格按照题目说明,Linux区分大小写,Windows不区分大小写;
  2. 源程序存放位置(D:\noip\)不一定;
    部分省份会在测评前用脚本处理源文件存放格式,
    删除命名不对/多余/存放路径不对/..的文件,一旦错了就没了。
    这里主要一点就是:如果考前通告中说明,不需要按照试题存放源文件,
    而是直接(D:\noip\),那么就需要按照官网通知来,注意官网信息。
    如果确实不清楚,考场询问监考老师,或者两种方式都复制一份保险。

下午测试讲评

开心小测

请大家在桌面新建文件夹,用自己中文名命名,将源程序(英文名.cpp)保存至该文件夹。

  • 文件输入输出,1S,512MB

身份证号码/idcard

题目描述

身份证号码是由十七位数字本体码和一位校验码组成。排列顺序从左到右依次为:六位数字“地址码”、八位数字“出生日期码”、三位数字“顺序码”和一位数字“校验码”。

“地址码”用来表示公民常住户口所在地区的行政区划代码;“出生日期码”表示公民的出生年月日;“顺序码”表示在同一“地址码”所表示的区域范围内,对同年同月同日出生的人编定的顺序号,顺序码的奇数分配给男性,偶数分配给女性。“校验码”是根据前面十七位数字计算得到,计算方法为:

\(1\) 步:将身份证号码乘以不同的系数,第 \(1\sim 17\) 位的系数分别为 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2;

\(2\) 步:将这 \(17\) 位数字和系数相乘的结果相加;

\(3\) 步:用加出来的和除以 \(11\),得到余数;

\(4\) 步:余数只可能有 \(0\sim10\)\(11\) 个数字,其分别对应的校验码为 1, 0, X, 9、8, 7, 6, 5, 4, 3, 2;也就是说如果上面得到的余数为 \(2\),那校验码就是 \(X\),如果余数为 \(10\),那校验码就是 \(2\)

现在你只记得自己身份证上的前 \(17\) 位,你能否不用回家拿身份证就可以知道最后一位是多少?

输入格式

输入只有一行,由 \(17\) 个数字组成,表示身份证号码的前 \(17\) 位,数字和数字之间用空格隔开。

输出格式

输出该身份证的最后一位校验码。

输入样例输出样例
4 4 2 0 0 0 1 9 9 6 0 1 0 1 0 2 3
4
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=110;
int n,m,a[N];
int b[]={7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
int c[]={ 1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2};

int main(){
    freopen("idcard.in", "r", stdin);
    freopen("idcard.out", "w", stdout);

    n = 17;
    for(int i=0; i<n; i++) cin>>a[i];
    int x=0;
    for(int i=0; i<n; i++) x += a[i] * b[i];
    x %= 11;
    if(x==2) cout<<char(c[x]);
    else cout<<c[x];

    fclose(stdin); fclose(stdout);
    return 0;
}

数位和/sum

对于一个整数,我们定义它的数位和为各个数位的和。

比如 \(456789\) 的数位和为 \(4+5+6+7+8+9\) 也就是 \(39\)

我们对这个 \(a\) 不停地求数位和,直到它不超过 \(9\),把所有的中间结果输出。

比如 \(a=456789\),那么它的数位和是 \(39\)。继续对 \(39\) 求数位和,得到 \(12\),继续对 \(12\) 操作,得到 \(3\)

输入格式

一个正整数 \(a\)

输出格式

若干行,为 \(a\) 不停地求数位和,直到不超过 \(9\) 为止的所有结果

输入样例输出样例
456789
39
12
3
86471648912748124790174817001304807
149
14
5

数据范围

\(50\%\)的数据,\(1\leq a\leq 10^9\)

\(80\%\)的数据,\(1\leq a\leq 10^{18}\)

\(100\%\)的数据,\(1\leq a\leq 10^{1000}\)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int n,m,a[N];
char s[N];

int main(){
    freopen("sum.in", "r", stdin);
    freopen("sum.out", "w", stdout);

    cin>>s; n = strlen(s);
    for(int i=0; i<n; i++) m += s[i]-'0';
    cout<<m<<endl;
    while(m>9){
        int t=m, a=0;
        while(t) a += t%10, t/=10;
        m = a;
        cout<<m<<endl;
    }

    fclose(stdin); fclose(stdout);
    return 0;
}

晨跑/running

题目描述

每天锻炼一小时,健康工作五十年,幸福生活一辈子。

在清华,体育运动绝对是同学们生活中不可或缺的一部分。为了响应学校的号召,模范好学生王队长决定坚持晨跑。不过由于种种原因,每天都早起去跑步不太现实,所以王队长决定每 \(a\) 天晨跑一次。换句话说,假如王队长某天早起去跑了步,之后他会休息 \(a-1\)天,然后第\(a\)天继续去晨跑,并以此类推。

王队长的好朋友小钦和小针深受王队长坚持锻炼的鼓舞,并决定自己也要坚持晨跑。为了适宜自己的情况,小钦决定每 \(b\) 天早起跑步一次,而小针决定每 \(c\) 天早起跑步一次。

某天早晨,王队长、小钦和小针在早起跑步时相遇了,他们非常激动、相互鼓励,共同完成了一次完美的晨跑。为了表述方便,我们把三位同学相遇的这天记为第 \(0\) 天。假设三位同学每次晨跑的时间段和路线都相同,他们想知道,下一次三人在跑步时相遇是第几天。由于三位同学都不会算,所以希望由聪明的你来告诉他们答案。

输入格式

输入共一行,包含三个正整数 \(a,b,c\),表示王队长每隔 \(a\) 天晨跑一次、小钦每隔 \(b\) 天晨跑一次且小针每隔 \(c\) 天晨跑一次。

输出格式

输出共一行,包含一个正整数 \(x\),表示三位同学下次将在第 \(x\) 天相遇。

输入样例输出样例
2 3 5
30
3 4 6
12
10 100 1000
1000

数据范围

\(\#1-5: 1≤a,b,c≤50\)

\(\#6-7: 1≤a,b,c≤1000\)

\(\#8-10: 1≤a,b,c≤10^5\)

分析:一句话题意,求三个数的最小公倍数。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1010;

LL gcd(LL a,LL b){
    return b?gcd(b,a%b) : a;
}
LL lcm(LL a,LL b){
    return a/gcd(a,b) * b;
}
int main(){
    freopen("running.in", "r", stdin);
    freopen("running.out", "w", stdout);

    LL a,b,c; cin>>a>>b>>c;
    cout<<lcm(lcm(a,b), c);

    fclose(stdin); fclose(stdout);
    return 0;
}

孤独的素数/prime

题目描述

在一个 \(n\)\(m\) 列的矩阵王国中,生活着一些整数,其中一些是素数,一些不是素数。

如果一个素数的上下左右、左上、右上、左下、右下相邻的数中都没有素数,我们就认为这是一个孤独的素数。

比如:一个 \(3\)\(5\) 列的矩阵如下。

3 8 10 9 5
6 10 2 4 13
8 8 9 6 3

这个矩阵中有 \(2\) 个素数,分别是第 \(1\) 行第 \(1\) 列的 \(3\),和第 \(2\) 行第 \(3\) 列的 \(2\)

请编程计算出,一个 \(n\)\(m\) 列的矩阵中有多少个孤独的素数?

输入格式

\(1\) 行有 \(2\) 个整数 \(n\)\(m\),代表矩阵的大小

接下来 \(n\) 行,每行有 \(m\) 个整数

输出格式

输出 \(1\) 个整数,代表矩阵中孤独素数的个数。

输入样例输出样例
3 5
3 8 10 9 5
6 10 2 4 13
8 8 9 6 3
2

数据范围

对于 \(100\%\) 的数据,\(3≤n,m≤50\),矩阵中的元素是\(1\)~\(1000\) 之间的整数。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=55;
int n,m,a[N][N],ans;
int dx[]={-1,1,0,0,-1,-1,1,1};
int dy[]={0,0,-1,1,-1,1,-1,1};

bool isp(int n){
    // [2, n-1] ---->   [2, sqrt(n)] ---> i<=n/i
    for(int i=2; i<=n/i; i++) 
        if(n%i==0) return 0;
    return n > 1;
}
int main(){
    freopen("prime.in", "r", stdin);
    freopen("prime.out", "w", stdout);

    cin>>n>>m;
    for(int i=1; i<=n; i++)
        for(int j=1; j<=m; j++) cin>>a[i][j];
    for(int i=1; i<=n; i++)
        for(int j=1; j<=m; j++){
            bool f=1;
            for(int k=0; k<8; k++){
                int tx = i+dx[k], ty=j+dy[k];
                if(tx>=1 && tx<=n &&ty>=1 &&ty <=m && isp(a[tx][ty])){
                    f=0; break;
                }
            }
            if(f && isp(a[i][j])) ans++;
        }
    cout<<ans;

    fclose(stdin); fclose(stdout);
    return 0;
}

博物馆/museum

题目描述

从前,有一个偌大的博物馆,每天都会有数以万计的人们来参观,欣赏这里的艺术作品。这一天,博物馆来了 \(n\) 批人,第 \(i\) 批人有 \(A_i\) 个人以及一个导游组成,他们依次到达,但同时也有一些批次的人离开,由于人次太多,博物馆的管理人员递给你一些人数表,就请你来统计一下剩下多少人。

输入格式

第一行是个整数 \(n\),接下来 \(n\) 行,每行两个数,第一个数 \(X\),如果 \(X=0\) 则后面接一个数 \(A_i\),表示来了 \(A_i\) 个人;如果 \(X=1\),那么接下来就有一个数 \(Y\),表示来的人中的第 \(Y\) 批离开了。

输出格式

一个数,表示剩下多少人。

输入样例输出样例
6
0 5
0 6
1 1
0 7
0 8
1 3
16

样例解释:有四批人,每批人要加上一位导游,分别是 \(6,7,8,9\) 人,离开的是第 \(1\)\(3\) 批,即走了 \(6+8=14\) 人,剩 \(7+9=16\) 人。

数据范围

\(\#1-3: 1≤n≤100,1≤A_i≤1000\)

\(\#4-10: 1≤n≤10^6,1≤A_i≤10^6\)

保证:\(X\) 只为 \(0\)\(1\)\(Y\) 一定符合要求。

分析:读清题目,使用 st[p] 表示 第 p 批人的数量。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e6+10;
int n,m,x,y,p,st[N];

int main(){
    freopen("museum.in", "r", stdin);
    freopen("museum.out", "w", stdout);

    cin>>n;
    for(int i=1; i<=n; i++){
        cin>>x>>y;
        if(x==0) st[++p] = y+1;
        else if(x==1) st[y] = 0;
    }
    LL ans=0;
    for(int i=1; i<=p; i++) ans += st[i];
    cout<<ans;

    fclose(stdin); fclose(stdout);
    return 0;
}
posted @ 2023-08-18 13:51  HelloHeBin  阅读(154)  评论(0)    收藏  举报