模拟与高精度(第二部分)

新手刷题网站,快速入门!洛谷

模拟与高精度(第二部分)


4.2

[1007]魔法少女小Scarlet

题目描述

略,模拟数组旋转

思路

顺时针:第i行,第j列 -> 倒数第j行,第i列

逆时针:第i行,第j列 -> 第j行,倒数第i列

代码

#include<iostream>
#include<cstring>
using namespace std;
int main(){
	int n,m,f,tmp=0;
	cin>>n>>m;
	int a[n][n],b[n][n];
// 	递增输入
	for(int i=0;i<n;i++) for(int j=0;j<n;j++) a[i][j] = b[i][j] = ++tmp;
// 	输入魔法+执行魔法
	for(int i=0;i<m;i++){
    	int x,y,r,z;
        cin>>x>>y>>r>>z;
        for(int i=-r;i<=r;i++) for(int j=-r;j<=r;j++) z?a[x-1+i][y-1+j]=b[x-1+j][y-1-i]:a[x-1+i][y-1+j]=b[x-1-j][y-1+i];
        for(int i=0;i<n;i++) for(int j=0;j<n;j++) b[i][j] = a[i][j];
	}
//  遍历输出
    for(int i=0;i<n;i++){
        int t=0;
	    for(int j=0;j<n;j++) t++?cout<<' '<<a[i][j]:cout<<a[i][j];
	    cout<<endl;
	}
	return 0;
}   

[NOIP2014 提高组] 生活大爆炸版石头剪刀布

题目描述

模拟猜拳题,总算遇到个简单题了

思路

直接暴力判断

代码

#include<iostream>
using namespace std;
int t,x,y,m,n;
int main(){
    cin>>t>>x>>y;
    int a[x],b[y];
    for(int i=0;i<x;i++) cin>>a[i];
    for(int i=0;i<y;i++) cin>>b[i];
    for(int i=0;i<t;i++) 
        // 判平
        if(a[i%x]==b[i%y]) continue;
        //判赢.总共就10种赢得情况
        else if(((a[i%x]==0)&&(b[i%y]==2||b[i%y]==3))||((a[i%x]==1)&&(b[i%y]==0||b[i%y]==3))||((a[i%x]==2)&&(b[i%y]==1||b[i%y]==4))||((a[i%x]==3)&&(b[i%y]==2||b[i%y]==4))||((a[i%x]==4)&&(b[i%y]==0||b[i%y]==1))) m++; 
        //判输
        else n++;
    cout<<m<<' '<<n;
	return 0;
}  

4月4日

[USACO2.4]两只塔姆沃斯牛 The Tamworth Two

题目描述

略,见题目链接

思路

无解的情况:

当牛和人同时再次出现在之前走过的地方,且牛和人的方向相同时,判断为无解

bool len[2000000];
//牛x+牛y*10+牛方向*100+人x*1000+人y*10000+人方向*100000,唯一值
int st = (x_c-1) + (y_c-1)*10 + (x_f-1)*100 + (y_f-1)*1000 + f_c * 10000 + f_f *100000;
if(!len[st]) len[st] = true;
else{
    cout<<0;
    return 0;
}

代码

#include<iostream>
#include<cstring>
using namespace std;
bool len[2000000];
//把移动单独拎出来
void move(int &flag,char a[][12],int &x,int &y){
    //先判断方向,再判断该方向下一步是否为障碍物
    //上
    if(flag==0&&a[x-1][y]!='*'){
        char t = a[x-1][y];
        a[x-1][y] = a[x][y];
        a[x--][y] = t; 
    //右
    }else if(flag==1&&a[x][y+1]!='*'){
        char t = a[x][y+1];
        a[x][y+1] = a[x][y];
        a[x][y++] = t; 
    //下
    }else if(flag==2&&a[x+1][y]!='*'){
        char t = a[x+1][y];
        a[x+1][y] = a[x][y];
        a[x++][y] = t; 
    //左
    }else if(flag==3&&a[x][y-1]!='*'){
        char t = a[x][y-1];
        a[x][y-1] = a[x][y];
        a[x][y--] = t; 
    //转向
    }else flag = (flag+1)%4;
}
int main(){
    //数组多两行两列,使其边界全是障碍物
    char a[12][12],b[12][12];
    memset(a,'*',12*12);
    memset(b,'*',12*12);
    int x_c,x_f,y_c,y_f;
    //牛和人分开到两个数组,防止出现人牛无限循环
    for(int i=1;i<=10;i++){
        for(int j=1;j<=10;j++){
            cin>>a[i][j];
            //a数组放牛,b数组放人
            a[i][j]=='C'?b[i][j]='.':b[i][j]=a[i][j];
            if(a[i][j]=='F') a[i][j]='.';
            if(a[i][j]=='C') x_c=i,y_c=j;
            if(b[i][j]=='F') x_f=i,y_f=j;
        }
    }
    int f_c,f_f,times;
    f_c=f_f=times=0;
    while(1){
        int st = (x_c-1) + (y_c-1)*10 + (x_f-1)*100 + (y_f-1)*1000 + f_c * 10000 + f_f *100000;
        //如果人和牛走到原来的路和原来的方向,循环结束,判断为误解
        if(!len[st]) len[st] = true;
        else{
             cout<<0;
             return 0;
        }
        move(f_c,a,x_c,y_c);
        move(f_f,b,x_f,y_f);
        times++;
        //如果人和牛的定位相同,循环结束,输出步数
        if(x_c==x_f&&y_c==y_f){
            break;
        }
    }
    cout<<times;
	return 0;
}  

[NOIP2009 普及组] 多项式输出

题目描述

模拟一元多项式(第二个觉得简单的题目),详见题目链接

思路

考虑三个方面:系数、次方、常数

系数为零,多项式正负号,系数为正负1时

次方大于1以及等于1的情况

前有多项式时,常数正负号,以及常数为0

前无多项式时,常数正负号,以及常数为0

代码

#include<iostream>
using namespace std;
int main(){
    int a;
    cin>>a;
    int b[a+1];
    for(int i=0;i<a+1;i++){
        cin>>b[i];
    }
    int t = a;
    //处理到常数之前
    for(int i=0;i<a;i++){
        //系数为0,只执行次方递减,
        if(b[i]==0){
            t--;
            continue;
        }
        //系数为正数且不为第一个数时添加加号
        if(b[i]>0&&i!=0) cout<<'+';
        //系数不为1或-1时输出系数
        if(b[i]*b[i]!=1) cout<<b[i];
        //系数为-1时输出负号
        if(b[i]==-1) cout<<'-';
        //次方大于1时显示自变量x和次方t
        if(t>1) cout<<"x^"<<t;
        //次方等于1时只显示自变量x
        if(t==1) cout<<"x";
        t--;
    }
    //常数单独拎出来
    //只有常数直接输出
    if(a==0) cout<<b[a];
    //前有自变量x,判断常数正负号以及是否为零
    else if(b[a]>0) cout<<'+'<<b[a];
    else if(b[a]<0) cout<<b[a];
    
}

4月5日

[NOIP2007 提高组] 字符串的展开

题目描述

将字符串折叠部分按规则展开,详见题目链接

思路

首先要考虑什么情况需要展开,比如 a-z、0-9、a-b、0-1等情况需要展开

什么情况不能展开,比如 -sdxva55、as35-、a-0、0-a、—、0-0、a-a、z-a、9-0等情况无需展开

其次对展开步骤进行分析

先考虑大写情况,只有字母展开需要大写,因此当规则为大写时,只分析字母就行;

接着,无论是大写情况下的数字,还是小写情况下的字母或数字,可以放一起考虑;

最后是*情况,这种情况比较简单

重复情况直接在输出时叠加for循环即可

逆序或顺序放在最外层考虑。

关于代码中的疑点,a[i+1] - a[i-1] < 26,因为字符 a - z 最大情况为 26,0 - 9 最大情况为 10,具体可查看ascii码表,但是有一种情况也满足 a[i+1] - a[i-1] < 26 ,那就是 - - 0 ,- 的 ascii 码为 45 ,0 的 ascii 码为 48 ,因此二者相减也小于26,但是这种情况是不能展开的,故当 a[i-1] ! = ‘-’。

代码

#include<iostream>
using namespace std;
char a[100000];
//展开操作
int ext(char a,char c,int x,int y,int z){
    //正序展开
    if(z==1){
        //转成大写的情况
        if(x==2&&'a'<=a&&a<='z'&&'a'<=c&&c<='z'){
            for(char i=a-31;i<c-32;i++){
                for(int j=0;j<y;j++){
                    cout<<i;
                }
            }
        //不用转成大写的情况
        }else if(x==1||x==2){
            for(char i=a+1;i<c;i++){
                for(int j=0;j<y;j++){
                    cout<<i;
                }
            }
        //转成*的情况
        }else{
            for(char i=a+1;i<c;i++){
                for(int j=0;j<y;j++){
                    cout<<'*';
                }
            }
        }
    //逆序展开
    }else if(z==2){
        //转成大写的情况
        if(x==2&&'a'<=a&&a<='z'&&'a'<=c&&c<='z'){
            for(char i=c-33;i>=a-31;i--){
                for(int j=0;j<y;j++){
                    cout<<i;
                }
            }
        //不用转成大写的情况
        }else if(x==1||x==2){
            for(char i=c-1;i>=a+1;i--){
                for(int j=0;j<y;j++){
                    cout<<i;
                }
            }
        //转成*的情况
        }else{
            for(char i=c-1;i>=a+1;i--){
                for(int j=0;j<y;j++){
                    cout<<'*';
                }
            }
        }
    }
    
}
int main(){
    int p1,p2,p3;
    cin>>p1>>p2>>p3;
    char t;
    int la=0;
    while(cin>>t) a[la++]=t;
    for(int i=0;i<la;i++){
        //当'-'不在头和尾、且'-'的前一位<'-'的后一位、且后一位减去前一位小于26、且前一位不是'-'时才能展开
        if(a[i]=='-'&&i!=0&&i!=la-1&&a[i-1]<a[i+1]&&a[i+1]-a[i-1]<26&&a[i-1]!='-'){
            ext(a[i-1],a[i+1],p1,p2,p3);
        }else{
            cout<<a[i];
        }
    }
}

帮贡排序

题目描述

略,见题目链接

i=0,s[i]为帮主,10<i<3,s[i]为副帮主,22<i<5,s[i]为护法,24<i<9,s[i]为长老,48<i<16,s[i]为堂主,715<i<41,s[i]为精英,2540<i时,s[i]为帮众,若干名

思路

除了帮主、副帮主以外,其他人员按照帮贡进行排序,排完序之后按照顺序给予职位,然后在各职位内部按照等级排序,如果等级相等,则按照输入的先后顺序排序,比如有7名堂主,在进行堂主内的排序时,一开始是按照帮贡排序的,但是输出时应该按照等级排序,故需要在职位内部进行二次排序,但是可能存在等级相同的情况,因此在这种情况下,则比较输入时的先后顺序,本题并未使用sort排序,而是用的冒泡排序。

代码

#include<iostream>
using namespace std;
string s[120][2];
int t[120][3];
//交换姓名、帮贡、等级、输入顺序
void swp(string x[120][2],int y[120][3],int m,int n){
    string a;
    int b;
    //交换姓名
    a = x[m][0];
    x[m][0] = x[n][0];
    x[n][0] = a;
    //交换帮贡
    b = y[m][0];
    y[m][0] = y[n][0];
    y[n][0] = b;
    //交换等级
    b = y[m][1];
    y[m][1] = y[n][1];
    y[n][1] = b;
    //交换输入顺序
    b = y[m][2];
    y[m][2] = y[n][2];
    y[n][2] = b;
}
//职位内部,先按照等级排序,再按照输入顺序排序
void swp2(string x[120][2],int y[120][3],int m,int n,int o){
    for(int i=m;i<n;i++){
        for(int j=i+1;j<n+1;j++){
            if(y[j][o]>y[i][o]) swp(x,y,i,j);
            else if(y[j][o]==y[i][o]&&y[j][o+1]<y[i][o+1]) swp(x,y,i,j);
        }
    }
}
int main(){
    int n;
    cin>>n;
    //依次输入姓名s[i][0]、职位s[i][1]、帮贡t[i][0]、等级t[i][1]
    for(int i=0;i<n;i++){
        cin>>s[i][0]>>s[i][1]>>t[i][0]>>t[i][1];
        //保存输入顺序
        t[i][2] = i;
    }
    //当存在帮主、和副帮主以外的人员时!!!进行按帮贡排序
    //这里数据保证必定有一名帮主和两名副帮主,且无权更改,因此从第3个开始即可
    if(n>3){
        for(int i=3;i<n-1;i++){
            for(int j=i+1;j<n;j++){
                if(t[j][0]>t[i][0]) swp(s,t,i,j);
            }
        }
    }
    //排序之后定职位
    for(int i=3;i<n;i++){
        if(i<5) s[i][1] = "HuFa";
        else if(i<9) s[i][1] = "ZhangLao";
        else if(i<16) s[i][1] = "TangZhu";
        else if(i<41) s[i][1] = "JingYing";
        else s[i][1] = "BangZhong";
    }
    //按照等级和输入顺序二次排序
    if(n>41){
        //护法排序
        swp2(s,t,3,4,1);
        //长老排序
        swp2(s,t,5,8,1);
        //堂主排序
        swp2(s,t,9,15,1);
        //精英排序
        swp2(s,t,16,40,1);
        //帮众排序
        swp2(s,t,41,n-1,1);
        //下面情况一样
    }else if(n>16){
        swp2(s,t,3,4,1);
        swp2(s,t,5,8,1);
        swp2(s,t,9,15,1);
        swp2(s,t,16,n-1,1);
    }else if(n>9){
        swp2(s,t,3,4,1);
        swp2(s,t,5,8,1);
        swp2(s,t,9,n-1,1);
    }else if(n>5){
        swp2(s,t,3,4,1);
        swp2(s,t,5,n-1,1);
    }else if(n>3){
        swp2(s,t,3,n-1,1);
    }
    //遍历输出
    for(int i=0;i<n;i++) cout<<s[i][0]<<' '<<s[i][1]<<' '<<t[i][1]<<endl;
    return 0;
}

4.8

阶乘数码

题目描述

求 n!中某个数码出现的次数。

思路

本题考查 高精度 * 单精度

代码

#include <iostream>
#include<cstring>
using namespace std;
int a[100000];
void mul(int x,int y){
    int j,up,len;
    up = j = 0;
    // 阶乘默认为1,因此数组长度默认为1
    len = a[0] = 1;
    for(int i=2;i<=x;i++){
        // 高精度 * 单精度
        for(j=0;j<len;j++){
            a[j] = a[j]*i+up;
            up = a[j]/10;
            a[j] = a[j]%10;
        }
        // 处理进位
        while(up>0){
            a[len++] = up%10;
            up = up/10;
        }
    }
    int ans = 0;
    for(int i=0;i<len;i++) if(a[i]==y) ans++;
    printf("%d\n",ans);
}
int main(){
    int n,x,y;
    scanf("%d",&n);
    while(n--){
        scanf("%d%d",&x,&y);
        memset(a,0,sizeof(a));
        mul(x,y);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值