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  阅读(203)  评论(0)    收藏  举报