day05:枚举&模拟&高精度(了解原理,实现高精加)&文件重定向

day05:枚举&模拟&高精度(了解原理,实现高精加)&文件重定向

枚举,其实就是穷举,把所有答案都遍历一遍,看是否满足要求

模拟:这个怎么说呢?其实就是让你干什么,你就干什么,按照它的要求来就是了。

对于枚举和模拟的题目主要是通过练题,提升自己的代码量来巩固,没有太多的知识点。

高精度

一个十分经典的问题:输入a b,求a+b的和
普通的话我们直接cout<<a+b就可以了,但是如果告诉你:

a,b是两个有100位长度的数据呢?这明显就不行了啊!
即使unsigned long long 的最大值也不过2^64=1.8e19

这就需要使用高精算法了,一般这类算法考的比较少,但是这样有趣的知识点,我们还是学习一下吧!

算法介绍

  a = 11111111
  b = 22222222
a+b = 33333333

  a = 8888,8888
  b = 9999,9999
a+b = 17 17 17 17, 17 17 17 17 (每位对应求和)
    = 17 17 17 17, 17 17 18  7 (开始进位)
    = 17 17 17 17, 17 18  8  7 (继续进位)
    = 17 17 17 17, 18  8  8  7 (继续进位)
    = 17 17 17 18,  8  8  8  7 (继续进位)
    = 17 17 17 18,  8  8  8  7 (继续进位)
    = 17 17 18  8,  8  8  8  7 (继续进位)
    = 17 18  8  8,  8  8  8  7 (继续进位)
    = 18  8  8  8,  8  8  8  7 (继续进位)
  = 1, 8  8  8  8,  8  8  8  7 (进位结束)

这就是高精度加法的原理,但是我们发现每次进位都是从后向前,
于是可以直接将数据翻转过来处理,最后输出或返回时在逆序即可。

以下为高精加法的实现

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

//注意开全局变量,如果是局部变量很容易出现问题
const int MAXN=10005;
int A[MAXN],B[MAXN],C[MAXN], Ans[MAXN],Len_A,Len_B,Len_Ans;

void Read(int A[],int &Len) {
    string cur;    cin>>cur;
    Len=cur.length();
    for(int i=0; i<Len; i++) A[i] = cur[i]-'0';
    reverse(A,A+Len);//对A[0]..A[Len]进行翻转
}
int main() {
    Read(A,Len_A);    Read(B,Len_B);
    Len_Ans=max(Len_A,Len_B);
    for(int i=0; i<=Len_Ans; i++) {
        Ans[i]=A[i]+B[i]+C[i];    //加上前一位的进位值
        if(Ans[i]>9) C[i+1]=Ans[i]/10, Ans[i]-=10;//处理进位值
    }
    while(Ans[Len_Ans]>0) Len_Ans++; //位数是否增加
    for(int i=Len_Ans-1; i>=0; i--)    cout<<Ans[i];//输出结果 
    return 0;
}//该高精模板源自CCF教材

以下为高精减法的实现

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

const int MAXN=10005;
int A[MAXN],B[MAXN],C[MAXN],Ans[MAXN],Len_A,Len_B,Len_Ans;

void Read(int A[],int &Len) {
    string cur;    cin>>cur;
    Len=cur.length();
    for(int i=0; i<Len; i++) A[i] = cur[i]-'0';
    reverse(A,A+Len);//对A[0]..A[Len]进行翻转
}

int main() {
    Read(A,Len_A);	Read(B,Len_B);
    Len_Ans=max(Len_A,Len_B);
    for(int i=0; i<=Len_Ans; i++) {
        Ans[i]=A[i]-B[i]-C[i];
        if(Ans[i]<0) C[i+1]++,Ans[i]+=10; //借位操作
    }
    while(Len_Ans>1&&Ans[Len_Ans-1]==0) Len_Ans--; //位数是否减少
    for(int i=Len_Ans-1; i>=0; i--) cout<<Ans[i];  //输出结果 
    return 0;
}//该高精模板源自CCF教材

以下为高精乘法的实现

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

const int MAXN=10005;
int A[MAXN],B[MAXN],C[MAXN],Ans[MAXN],Len_A,Len_B,Len_Ans;

void Read(int A[],int &Len) {
    string cur;	cin>>cur;
    Len=cur.length();
    for(int i=0; i<Len; i++) A[i] = cur[i]-'0';
    reverse(A,A+Len);
}

int main() {
    Read(A,Len_A);    Read(B,Len_B);
    Len_Ans=Len_A+Len_B-1;
    for(int i=0; i<=Len_A; i++)
        for(int j=0; j<=Len_B; j++)
            Ans[i+j]+=A[i]*B[j];
    for(int i=0; i<Len_Ans; i++)
        if(Ans[i]>9) {
            Ans[i+1]+=Ans[i]/10;
            Ans[i]%=10;
        }//最后进行进位处理
    while(Ans[Len_Ans]) Len_Ans++;
    for(int i=Len_Ans-1; i>=0; i--) cout<<Ans[i];
    return 0;
}//该高精模板源自CCF教材

以下为高精除法的实现

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

const int MAXN=10005;
int A[MAXN],B[MAXN],C[MAXN],Ans[MAXN],Len_A,Len_B,Len_Ans;

void Read(int A[]) {
    string cur;	cin>>cur;
    A[0]=cur.length();
    for(int i=1; i<=A[0]; i++)    A[i] = cur[i-1]-'0';
    reverse(A+1,A+A[0]+1);
}

bool Big(){//比较余数C与除数B的大小,如果C>=B返回True,否则返回false
    if(C[0]>B[0]) return true;
    if(C[0]<B[0]) return false;
    for(int i=C[0]; i>=1; i--)
        if(C[i]<B[i])return false;
        else if(C[i]>B[i]) return true;
    return true;
}

void Minus() {//从C中减去B
    int c=0;
    for(int i=1; i<=C[0]; i++) {
        C[i]-=B[i]+c;
        if(C[i]<0) C[i]+=10, c=1;
        else c=0;
    }
    while(C[0]>1&&C[C[0]]==0) C[0]--;
}

void output(int A[]) {
    for(int i=A[0]; i>=1; i--)
        cout<<A[i];
    cout<<endl;
}

int main() {
    Read(A); Read(B);
    C[0]=0;
    for(int i=A[0]; i>=1; i--) {
        for(int j=C[0]; j>=1; j--) C[j+1]=C[j];
        C[1]=A[i];
        C[0]++;
        while(Big()) {
            Minus();
            Ans[i]++;
        }
    }
    Ans[0]=A[0];
    while(Ans[0]>1&&Ans[Ans[0]]==0) Ans[0]--;
    output(Ans);
    output(C);
    return 0;
}//该高精模板源自CCF教材

高精加减乘的实现原理是大同小异的,高精除法需要转化使用减法的方式比较麻烦,但是很少考到这个,建议就是如果有时间可以将高精加减乘按照自己的风格写一遍。

另外注意一点:部分同学喜欢将计算结果返回为string类型,当然笔者也喜欢这样!
可是在string使用是会用到str.append()的用法,而这样的用法是在C11版本才有的,如果不支持C11那么这样的写法是不能AC的,比如:提交奥赛一本通的网站就会出bug

文件重定向

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

freopen("输入文件名", "r", stdin); //替代我们的手动输入,将文件中内容读入输入流中
freopen("输出文件名", "w", stdout);//将输出流中的数据写入文件中

//正常的执行程序

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

在 windows 系统上可以不写fclose,系统会自动关闭,
但是 Linux 系统上如果不写会出现问题,无法正常关闭或文件保存出现问题,保险起见,还是写上。

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

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

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

最后应该提交的的源文件,应当命名为:ab.cpp,并存放如下内容

#include<iostream>
using namespace std;
int main() {
    freopen("ab.in", "r", stdin);    //读入文件
    freopen("ab.out", "w", stdout);  //输出文件

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

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

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

另外注意一点:题目一般会告诉你,我要提交什么样的源文件,比如 ab.cpp

1. P2670 [NOIP2015 普及组] 扫雷游戏

【题目描述】扫雷游戏是一款十分经典的单机小游戏。
在 n行 m列的雷区中有一些格子含有地雷(称之为地雷格),其他格子不含地雷(称之为非地雷格)。
玩家翻开一个非地雷格时,该格将会出现一个数字——提示周围格子中有多少个是地雷格。
游戏的目标是在不翻出任何地雷格的条件下,找出所有的非地雷格。

现在给出 n行 m列的雷区中的地雷分布,要求计算出每个非地雷格周围的地雷格数。
注:一个格子的周围格子包括其上、下、左、右、左上、右上、左下、右下八个方向上与之直接相邻的格子。

输入格式:
第一行是用一个空格隔开的两个整数 n和 m,分别表示雷区的行数和列数。
接下来 n行,每行 m个字符,描述了雷区中的地雷分布情况。
字符 '*' 表示相应格子是地雷格,字符 '?' 表示相应格子是非地雷格。相邻字符之间无分隔符。

输出格式:
输出文件包含 n行,每行 m个字符,描述整个雷区。用 '*' 表示地雷格,用周围的地雷个数表示非地雷格。
相邻字符之间无分隔符。

输入样例:

3 3
*??
???
?*?

输出样例:

*10
221
1*1

数据范围:对于 100% 的数据, 1≤n≤100, 1≤m≤100。

题解:按照九宫格的思想对字符串数组进行遍历即可,最后九宫格中中间存放的是该九宫格中地雷数

#include<bits/stdc++.h>
using namespace std;
const int N=200;
char a[N][N];//字符数组存放输入的字符 
int b[N][N];//整型数组存放以ij为中心的九宫格的地雷数 
int main() {
    int n,m;    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++) {
            if(a[i-1][j-1]=='*') b[i][j]++;//b[i][j]=b[i][j]+1;
            if(a[i-1][j]=='*')   b[i][j]++;//地雷数量+1
            if(a[i-1][j+1]=='*') b[i][j]++;

            if(a[i][j-1]=='*') b[i][j]++;
            if(a[i][j+1]=='*') b[i][j]++;

            if(a[i+1][j-1]=='*') b[i][j]++;
            if(a[i+1][j]=='*')   b[i][j]++;
            if(a[i+1][j+1]=='*') b[i][j]++;
        }
    }
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=m; j++) {
            if(a[i][j]=='*') cout<<a[i][j];//如果是地雷就输出地雷 
            else cout<<b[i][j];//不是地雷输出该九宫格的地雷数 
        } cout<<endl;
    } return 0;
}

2. P1003 [NOIP2011 提高组] 铺地毯

【题目描述】为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯。
一共有 n 张地毯,编号从 1 到 n。
现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上。

地毯铺设完成后,组织者想知道覆盖地面某个点的最上面的那张地毯的编号。
注意:在矩形地毯边界和四个顶点上的点也算被地毯覆盖。

输入格式:输入共 n+2 行。第一行,一个整数 n,表示总共有 n 张地毯。
接下来的 n 行中,第 i+1 行表示编号 i 的地毯的信息,包含四个整数 a ,b ,g ,k,
每两个整数之间用一个空格隔开,分别表示铺设地毯的左下角的坐标 (a,b) 以及地毯在 x 轴和 y 轴方向的长度。
第 n+2 行包含两个整数 x 和 y,表示所求的地面的点的坐标 (x, y)。

输出格式:
输出共 1 行,一个整数,表示所求的地毯的编号;若此处没有被地毯覆盖则输出 -1。

输入样例

3
1 0 2 3
0 2 3 3
2 1 3 3
2 2

输出样例:3

数据范围:
对于 30% 的数据,有 n≤2。
对于 50% 的数据,有 0≤a,b,g,k≤100。
对于 100% 的数据,有 0≤n≤10。

题解:题目要最上面的地毯编号,那么可以直接从后向前判断,如果发现地毯就输出,并结束。

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+1;
int a[N],b[N],g[N],k[N];
int main(){
    int n; cin>>n;
    for(int i=1; i<=n; i++){
        cin>>a[i]>>b[i]>>g[i]>>k[i];
    }
    int x,y; cin>>x>>y;
    for(int i=n; i>=1; i--){//注意逆序查找,保证查找的是最上面的地毯
        if(x>=a[i] && x<=a[i]+g[i] && y>=b[i] && y<=b[i]+k[i]){
            cout<<i; return 0;//找到结果就退出 
        }
    }
    cout<<-1; return 0;
} 

3. P1067 [NOIP2009 普及组] 多项式输出

一元n次多项式可用如下的表达式表示:

\[f(x) = a_nx^n + a_{n-1} x^{n-1} +...+a_1x+a_0, a_n!=0 \]

给出一个一元多项式各项的次数和系数,请按照如下规定的格式要求输出该多项式:

  1. 多项式中自变量为x,从左到右按照次数递减顺序给出多项式。
  2. 多项式中只包含系数不为0的项。
  3. 如果多项式n次项系数为正,则多项式开头不出现“+”号,如果多项式n次项系数为负,则多项式以“-”号开头。
  4. 对于不是最高次的项,以“+”号或者“-”号连接此项与前一项,分别表示此项系数为正或者系数为负。
    紧跟一个正整数,表示此项系数的绝对值(如果一个高于0次的项,其系数的绝对值为1,则无需输出 1)。
    如果x的指数大于1,则接下来紧跟的指数部分的形式为“x^b”,其中 b 为 x 的指数;
    如果 x 的指数为 1,则接下来紧跟的指数部分形式为“x”;
    如果 x 的指数为0,则仅需输出系数即可。
  5. 多项式中,多项式的开头、结尾不含多余的空格。

输入格式:
输入共有 2 行,第一行1 个整数n,表示一元多项式的次数。
第二行有 n+1个整数,其中第 i 个整数表示第 n-i+1 次项的系数,每两个整数之间用空格隔开。

输出格式:
输出共 1 行,按题目所述格式输出多项式。

输入样例

5 
100 -1 1 -3 0 10

输出样例:

100x^5-x^4+x^3-3x^2+10

数据范围:对于100%数据,0≤n≤100,−100≤系数 ≤100。

#include<bits/stdc++.h>
using namespace std;
int a[101];
int main(){
    int n;cin>>n;
    for(int i=n; i>=0; i--)    cin>>a[i];
    for(int i=n; i>=0; i--){
        if(i==n){
            if(a[i]>0){
                if(a[i]==1)    cout<<"x^"<<i; 
                else cout<<a[i]<<"x^"<<i;
            }else if(a[i]<0){
                if(a[i]==-1) cout<<"-x^"<<i;
                else cout<<a[i]<<"x^"<<i; 
            }
        }else if(i==0){
            if(a[i]>0){
                cout<<"+"<<a[i];
            }else if(a[i]<0){
                cout<<a[i];
            }
        }else if(i==1){
            if(a[i]>0){
                if(a[i]==1)    cout<<"+x"; 
                else cout<<"+"<<a[i]<<"x";
            }else if(a[i]<0){
                if(a[i]==-1) cout<<"-x";
                else cout<<a[i]<<"x"; 
            }
        }else{
            if(a[i]>0){
                if(a[i]==1)    cout<<"+"<<"x^"<<i; 
                else cout<<"+"<<a[i]<<"x^"<<i;
            }else if(a[i]<0){
                if(a[i]==-1)    cout<<"-x^"<<i; 
                else cout<<a[i]<<"x^"<<i;
            }
        } 
    }return 0;
}
//当然还有更简短的方法
#include<stdio.h>
#include<math.h>
int main(){
    int n,arr[105];
    scanf("%d",&n);
    for(int i=0;i<=n;i++) scanf("%d",&arr[i]);
    for(int i=0,k=n;i<=n;i++,k--){
        if(arr[i]==0) continue;
        if(k!=n&&arr[i]>0) printf("+");
        if(abs(arr[i])>1||k==0) printf("%d",arr[i]);
        if(arr[i]==-1&&k) printf("-");
        if(k>1) printf("x^%d",k);
        if(k==1) printf("x");
    }
    return 0;
}

4. P2615 [NOIP2015 提高组] 神奇的幻方

【题目描述】

幻方是一种很神奇的 NxN矩阵:它由数字1,2,3,⋯,NxN构成,且每行、每列及两条对角线上的数字之和都相同。
当 N 为奇数时,我们可以通过下方法构建一个幻方:
首先将 1 写在第一行的中间。
之后,按如下方式从小到大依次填写每个数K=2,3,⋯,NxN) :

  1. 若 (K-1) 在第一行但不在最后一列,则将 K填在最后一行, (K-1)所在列的右一列;
  2. 若 (K−1) 在最后一列但不在第一行,则将 K填在第一列, (K-1)所在行的上一行;
  3. 若 (K−1) 在第一行最后一列,则将 KK 填在 (K-1)的正下方;
  4. 若 (K−1) 既不在第一行,也不在最后一列,如果 (K-1)的右上方还未填数,则将 K填 (K−1) 的右上方,否则将K填在 (K-1)的正下方。

现给定 N,请按上述方法构造NxN 的幻方。

输入格式:一个正整数 N,即幻方的大小。
输出格式:共 N 行 ,每行N个整数,即按上述方法构造出的 NxN的幻方,相邻两个整数之间用单空格隔开。

输入样例:3
输出样例:

8 1 6
3 5 7
4 9 2

数据范围:对于100%的数据,对于全部数据,1≤N≤39 且 N 为奇数。

题解:本题属于模拟题,按照题目要求来模拟即可,但是要注意界限问题

#include<iostream>
using namespace std;
const int N=40;
int a[N][N];
int main() {
    int n; cin>>n;
    int mid = n/2+1, cnt=1;
    a[1][mid] = cnt = 1;

    int h=1, l=mid;
    while(cnt<=n*n) {
        if(h==1 && l!=n) {
            h = n;
            l = l+1;
            a[h][l] = ++cnt;
        }

        if(l==n && h!=1) {
            h = h-1;
            l = 1;
            a[h][l] = ++cnt;
        }

        if(h==1 && l==n) {
            h = h+1;
            a[h][l] = ++cnt;
        }

        if(h!=1 && l!=n) {
            if(a[h-1][l+1]==0) {
                h = h-1;
                l = l+1;
                a[h][l] = ++cnt;
            } else {
                h = h+1;
                l = l;
                a[h][l] = ++cnt;
            }
        }
    }

    for(int i=1; i<=n; i++) {
        for(int j=1; j<=n; j++) {
            cout<<a[i][j]<<" ";
        }cout<<endl;
    } return 0;
}

5. P2141 [NOIP2014 普及组] 珠心算测验

【题目描述】珠心算是一种通过在脑中模拟算盘变化来完成快速运算的一种计算技术。
珠心算训练,既能够开发智力,又能够为日常生活带来很多便利,因而在很多学校得到普及。

某学校的珠心算老师采用一种快速考察珠心算加法能力的测验方法。
他随机生成一个正整数集合,集合中的数各不相同,然后要求学生回答:其中有多少个数,恰好等于集合中另外两个(不同的)数之和?

最近老师出了一些测验题,请你帮忙求出答案。

输入格式:
共两行,第一行包含一个整数n,表示测试题中给出的正整数个数。
第二行有n个正整数,每两个正整数之间用一个空格隔开,表示测试题中给出的正整数。

输出格式:一个整数,表示测验题答案。

输入样例:

4
1 2 3 4

输出样例:2

样例说明:由1+2=3,1+3=4,故满足测试要求的答案为2。
注意,加数和被加数必须是集合中的两个不同的数。

数据范围:对于100%的数据,3≤n≤100,测验题给出的正整数大小不超过10,000。

题解:最暴力的方法,直接枚举

#include<bits/stdc++.h>
using namespace std;
const int N = 10005; 
int a[N],b;
int main(){
    int n;cin>>n;
    for(int i=0; i<n; i++) cin>>a[i];
    int ans=0;  sort(a,a+n);//排序一下 
    for(int i=2; i<n; i++){
        for(int j=0; j<i; j++){
            bool flag = 0; 
            for(int k=1; k<i; k++){
                if(a[i]==a[j]+a[k] && j!=k){//加数和被加数不同 
                    flag = 1;break;
                }
            }
            if(flag) ans++;
        }
    }
    cout<<ans; return 0;
}

6. P1055 [NOIP2008 普及组] ISBN 号码

【题目描述】每一本正式出版的图书都有一个ISBN号码与之对应,
ISBN码包括 9 位数字、1 位识别码和 3 位分隔符,其规定格式如 x-xxx-xxxxx-x,
其中符号-就是分隔符(键盘上的减号),最后一位是识别码,例如 0-670-82162-4 就是一个标准的ISBN码。
ISBN码的首位数字表示书籍的出版语言,例如0代表英语;
第一个分隔符-之后的三位数字代表出版社,例如670代表维京出版社;
第二个分隔符后的五位数字代表该书在该出版社的编号;最后一位为识别码。识别码的计算方法如下:

首位数字乘以 1 加上次位数字乘以 2…… 以此类推,用所得的结果 mod 11,所得的余数即为识别码,
如果余数为 10,则识别码为大写字母X。
例如ISBN号码 0-670-82162-4 中的识别码 4 是这样得到的:对 067082162 这 9 个数字,
从左至右,分别乘以 1,2,...,9 再求和,即 0×1+6×2+……+2×9=158,然后取 11158 mod 11 的结果 4 作为识别码。

你的任务是编写程序判断输入的ISBN号码中识别码是否正确,
如果正确,则仅输出Right;
如果错误,则输出你认为是正确的ISBN号码。

输入格式:一个字符序列,表示一本书的ISBN号码(保证输入符合ISBN号码的格式要求)。

输出格式:一行,假如输入的ISBN号码的识别码正确,那么输出Right,否则,按照规定的格式,输出正确的ISBN号码(包括分隔符-)。

输入样例:0-670-82162-4
输出样例:Right
输入样例:0-670-82162-0
输出样例:0-670-82162-4

题解:

#include<iostream>
using namespace std;
char a[14];
int main() {
    for(int i=1; i<=13; i++) cin>>a[i];
    int x = ((a[1]-'0')*1 +
            (a[3]-'0')*2+(a[4]-'0')*3+(a[5]-'0')*4+(a[7]-'0')*5+(a[8]-'0')*6+
            (a[9]-'0')*7+(a[10]-'0')*8+(a[11]-'0')*9) % 11;
    bool flag = ((a[13]-'0') == x || (x==10 && a[13]=='X'));
    if(flag) {
        cout<<"Right"<<endl;
    } else {
        for(int i=1; i<=12; i++) cout<<a[i];
        if(x==10) cout<<"X";
        else cout<<x;
    }return 0;
}

7. P1042 [NOIP2003 普及组] 乒乓球

【题目背景】国际乒联现在主席沙拉拉自从上任以来就立志于推行一系列改革,以推动乒乓球运动在全球的普及。
其中 11 分制改革引起了很大的争议,有一部分球员因为无法适应新规则只能选择退役。
华华就是其中一位,他退役之后走上了乒乓球研究工作,意图弄明白 11 分制和 21 分制对选手的不同影响。
在开展他的研究之前,他首先需要对他多年比赛的统计数据进行一些分析,所以需要你的帮忙。

【题目描述】华华通过以下方式进行分析,首先将比赛每个球的胜负列成一张表,然后分别计算在 11 分制和 21 分制下,双方的比赛结果(截至记录末尾)。

比如现在有这么一份记录,(其中 W 表示华华获得一分,L 表示华华对手获得一分):WWWWWWWWWWWWWWWWWWWWWWLW

在 11分制下,此时比赛的结果是华华第一局 11 比 0 获胜,第二局 11 比 0 获胜,正在进行第三局,当前比分 1 比 1。
而在 21 分制下,此时比赛结果是华华第一局 21 比 0 获胜,正在进行第二局,比分 2 比 1。
如果一局比赛刚开始,则此时比分为 0 比 0。直到分差大于或者等于 2,才一局结束。

你的程序就是要对于一系列比赛信息的输入(WL 形式),输出正确的结果。

输入格式:
每个输入文件包含若干行字符串,字符串有大写的 W,L 和 E 组成。
其中E 表示比赛信息结束,程序应该忽略 E之后的所有内容。
每行至多 25 个字母,最多有2500 行。

输出格式:
输出由两部分组成,每部分有若干行,每一行对应一局比赛的比分(按比赛信息输入顺序)。
其中第一部分是 11 分制下的结果,第二部分是 21 分制下的结果,两部分之间由一个空行分隔。

输入样例:

WWWWWWWWWWWWWWWWWWWW
WWLWE

输出样例:

11:0
11:0
1:1

21:0
2:1

题解:这是关于字符串的一个模拟题,对于字符串的题目,需要的是冷静思考,不断Debug

#include<iostream>
#include<cmath>
using namespace std;
int t11[6000][3];
int t21[3000][3];
int main() {
    char s;
    int i=1,j=1;//局数
    do {
        cin>>s;
        if(s=='W') {
            t11[i][1]++;
            t21[j][1]++;
        }
        if(s=='L') {
            t11[i][2]++;
            t21[j][2]++;
        }
        if((abs(t11[i][1]-t11[i][2])>=2) && ((t11[i][1]>=11)||(+t11[i][2]>=11))) i++;
        if((abs(t21[j][1]-t21[j][2])>=2) && ((t21[j][1]>=21)||(+t21[j][2]>=21))) j++;
    } while(s!='E');
    
    for(int k=1; k<=i; k++){
        cout<<t11[k][1]<<":"<<t11[k][2]<<endl;
    }
    cout<<endl;
    for(int k=1; k<=j; k++){
        cout<<t21[k][1]<<":"<<t21[k][2]<<endl;
    }return 0;
}

补充. U169789 蛇形输出 - 二维数组

【题目描述】输入两个数,代表n行m列,然后从1开始蛇形输出1~n*m的方阵,且方阵中每个数字占5个宽度

输入格式:输入两个数,代表n行m列

输出格式:输出一个方阵,且方阵中每个数字占5个宽度

输入样例:3 4

输出样例:

    1    2    3    4
    8    7    6    5
    9   10   11   12

题解:

#include<bits/stdc++.h>
using namespace std;
const int N=1e4;
int a[N][N];

//程序先读入两个数,代表n行m列,然后从1开始蛇形输出1~n*m
int main(){
    int n=3,m=4; cin>>n>>m;//行,列 
    int k=0, i=0, j=0;
    while(k<n*m) {
        while(k<n*m && j<m){//向右 
            a[i][j++] = ++k;
        }
        i++;
        while(k<n*m && j>0){//向左 
            a[i][--j] = ++k;
        }
        i++;
    }
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            printf("%5d",a[i][j]);//cout<<setw(5)<<a[i][j];//保留5位宽度
        }cout<<endl;
    }
    return 0;
}

补充. U169790 图像旋转 - 二维数组

【题目描述】输入一个n行m列的黑白图像,将它顺时针旋转90°后输出。

输入格式:

第一行包含两个整数n和m,表示图像包含像素点的行数和列数。

1<=n<=100,1<=m<=100;

接下来n行,每行m个整数,表示每个图像的每个像素点灰度。

相邻两个整数之间用单个空格隔开,每个元素均在0~255之间。

输出格式:

输出m行,每行n个整数,为顺时针旋转90°后的图像。

图像中每个数字占5个宽度

输入样例:

3 3
1 2 3
4 5 6
7 8 9

输出样例:

7 4 1
8 5 2
9 6 3

题解:本类题目主要是根据下标找到规律,要养成习惯,根据下标找到规律

3 3
1 2 3
4 5 6
7 8 9

7 4 1
8 5 2
9 6 3
//根据下标找到规律
11 12 13 14 
21 22 23 24
31 32 33 34
41 42 43 44

41 31 21 11
42 32 22 12
43 33 23 13
44 34 24 14
#include<bits/stdc++.h>
using namespace std;
const int N=1e4;
int a[N][N];
int main() {
    int n,m; cin>>n>>m;
    for(int i=0; i<n; i++) {
        for(int j=0; j<m; j++) {
            cin>>a[i][j];
        }
    }
    for(int i=0; i<m; i++) {
        for(int j=n-1; j>=0; j--) {
            cout<<setw(5)<<a[j][i];
        }cout<<endl;
    }return 0;
}
posted @ 2021-08-04 15:52  HelloHeBin  阅读(219)  评论(0编辑  收藏  举报