新手刷题网站,快速入门!洛谷
模拟与高精度(第二部分)
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]为帮主,1名
0<i<3时,s[i]为副帮主,2名
2<i<5时,s[i]为护法,2名
4<i<9时,s[i]为长老,4名
8<i<16时,s[i]为堂主,7名
15<i<41时,s[i]为精英,25名
40<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;
}