一、题解
1、A-[NOIP2013]记数问题_2024春算法训练3——数组与字符串 (nowcoder.com)
直接暴力用一个哈希表存每个数出现的次数,最坏的时间时间复杂度为7*10^7(实际上比这个数要小);代码如下:
#include<iostream>
using namespace std;
int ha[10];int main()
{int r,q;cin>>r>>q;for(int i=1;i<=r;i++){int t=i;while(t){ha[t%10]++;t/=10;}}cout<<ha[q]<<endl;return 0;
}
2、B-[NOIP2005]校门外的树_2024春算法训练3——数组与字符串 (nowcoder.com)
这题我只知道两个时间复杂度不同的解法,一个是线性时间复杂度的,一个是O(nm)的;
首先说一下第二种,其实就是直接模拟,每次从起点到终点减去1,如果一颗树没有被挖掉,那么它的值为0,反之小于0;代码如下:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;const int N=200010;
int a[N],b[N];void solve()
{int n,m;cin>>n>>m;while(m--){int x,y;cin>>x>>y;for(int i=x;i<=y;i++)a[i]--;}int cnt=0;for(int i=0;i<=n;i++)if(a[i]==0)cnt++;cout<<cnt<<endl;
}int main()
{int _;_=1;while(_--){solve();}return 0;
}
第二种用了差分算法,这个算法与前缀和算法互逆关于算法的知识可以看一下这个视频:
STUACM-算法入门-前缀和与差分(含二维)_哔哩哔哩_bilibili
代码如下:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;const int N=200010;
int a[N],b[N];void insert(int x,int y)
{b[x]--;b[y+1]++;
}void solve()
{int n,k;cin>>n>>k;while(k--){int x,y;cin>>x>>y;insert(x,y);}int ans=0;for(int i=1;i<=n;i++)b[i]+=b[i-1];for(int i=0;i<=n;i++)if(b[i]<0)ans++;cout<<n+1-ans<<endl;
}int main()
{int _;_=1;while(_--){solve();}return 0;
}
3、C-比较月亮大小_2024春算法训练3——数组与字符串 (nowcoder.com)
如果只有一天的话只能判断0和15这两个特殊元素,其他的都不能判断,如果有两天以上的话只用看最后两天可以了(这种情况只有14,15需要特判)。代码如下:
#include<iostream>
using namespace std;int temp[1000];int main()
{int n;cin>>n;for(int i=1;i<=n;i++)cin>>temp[i];if(n<=1){if(temp[n]==15)cout<<"DOWN"<<endl;else if(temp[n]==0)cout<<"UP"<<endl;else cout<<-1<<endl;}else if(temp[n]==15&&temp[n-1]==14)cout<<"DOWN"<<endl;else if(temp[n]>temp[n-1])cout<<"UP"<<endl;else if(temp[n]<temp[n-1])cout<<"DOWN"<<endl;return 0;
}
4.D-求逆序数_2024春算法训练3——数组与字符串 (nowcoder.com)
本题根据数据范围判断可以有两种解法,第一种是根据题目暴力枚举O(n^2),二是利用归并排序的特性求得O(nlogn);
第二种做法采用了分治的思想,非常经典,首先看归并排序的流程:
1.划分区间 [l,mid] ,[ mid+1,r];
2.递归排序(不断减小问题的规模)
3.归并,将左右两个区间合二为一;
一个逆序对是指一对数,其中前面的元素严格大于后面的数;那么根据归并排序的过程我们可以将逆序对分成三类:
1.两个数都在左边
2.两个数都在右边
3.两个数分别在左右两边
其实质就是计算第三种逆序对,因为左右两边的逆序对随着递归最终都会分解成第三种情况。
注意退出循环时还有一个数组肯定是有一个数组没有枚举完的所以,那个数组剩下的数一定要记得加进临时数组
代码如下:
#include<iostream>
using namespace std;
int ans=0;int temp[2010],a[2022];/*void merge_sort(int q[],int l,int r)
{if(l>=r)return ;int mid=(l+r)>>1;merge_sort(q,l,mid);merge_sort(q,mid+1,r);int i=l,j=mid+1,k=0;while(i<=mid&&j<=r){if(q[i]>=q[j])ans+=mid-i+1,temp[k++]=q[j++];else temp[k++]=q[i++];}while(i<=mid)temp[k++]=q[i++];while(j<=r)temp[k++]=q[j++];for(int i=0,j=l;j<=r;j++,i++)q[j]=temp[i];
}*/int main()
{int n;cin>>n;for(int i=0;i<n;i++)cin>>a[i];merge_sort(a,0,n-1);for(int i=0;i<n;i++)for(int j=i;j<n;j++)if(a[i]>a[j])ans++;cout<<ans<<endl;return 0;
}
5.E-F课程满意度计算_2024春算法训练3——数组与字符串 (nowcoder.com)
用一个哈希表记录每门课程的人数,看其是否等于总人数
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;const int N=1010;
int a[N][N],ha[N];void solve()
{int n,m;cin>>n>>m;int d=n;while(d--){int x;cin>>x;while(x--){int y;cin>>y;ha[y]++;}}int cnt=0;for(int i=1;i<=m;i++)if(ha[i]==n)cnt++;cout<<cnt<<endl;
}int main()
{int _;_=1;while(_--){solve();}return 0;
}
6.F-有序序列合并_2024春算法训练3——数组与字符串 (nowcoder.com)
普通排序
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;const int N=200010;
int a[N];bool cmp(int a,int b)
{return a<b;
}void solve()
{int n,m;cin>>n>>m;n+=m;for(int i=1;i<=n;i++)cin>>a[i];sort(a+1,a+1+n,cmp);for(int i=1;i<=n;i++)cout<<a[i]<<" ";
}int main()
{int _;_=1;while(_--){solve();}return 0;
}
7.G-[NOIP2015]扫雷游戏_2024春算法训练3——数组与字符串 (nowcoder.com)
遍历整张图如果不是雷就检查其周围有多少颗雷
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;const int N=110;
char f[N][N];int dx[]={-1,0,1,0,1,1,-1,-1},dy[]={0,1,0,-1,1,-1,1,-1};void check(int x,int y)
{int cnt=0;for(int i=0;i<8;i++){int xx=x+dx[i],yy=dy[i]+y;if(f[xx][yy]=='*')cnt++;}f[x][y]='0'+cnt;
}void solve()
{int a,b;cin>>a>>b;for(int i=1;i<=a;i++)for(int j=1;j<=b;j++)cin>>f[i][j];for(int i=1;i<=a;i++){ for(int j=1;j<=b;j++){if(f[i][j]!='*')check(i,j);printf("%c",f[i][j]);}cout<<endl;}
}int main()
{int _;_=1;while(_--){solve();}return 0;
}
8.H-数独合理吗?_2024春算法训练3——数组与字符串 (nowcoder.com)
简单模拟,用一个数组记录数字出现的次数即可,记得每次检查前要初始化这个数组,代码如下:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;const int N=10;
int shu[N][N],ha[10];
bool flag1=1,flag2=1,flag3=1;void init()
{for(int i=1;i<=10;i++)ha[i]=0;
}bool check3(int x,int y)
{for(int i=x;i<=x+2;i++)for(int j=y;j<=y+2;j++){ha[shu[i][j]]++;if(ha[shu[i][j]]>1)return false;}return true;
}void check1()
{for(int i=1;i<=9;i++){init();for(int j=1;j<=9;j++){ha[shu[i][j]]++;if(ha[shu[i][j]]>1)flag1=false;}} for(int i=1;i<=9;i++){init();for(int j=1;j<=9;j++){ha[shu[j][i]]++;if(ha[shu[j][i]]>1)flag2=false;}}
}void check2()
{for(int i=1;i<=9;i+=3)for(int j=1;j<=9;j+=3){init();if(!check3(i,j))flag3=false;}
}void solve()
{for(int i=1;i<=9;i++)for(int j=1;j<=9;j++)cin>>shu[i][j];/*检查行和列*/check1();/*检查宫*/check2();if(flag1&&flag2&&flag3)cout<<"YES"<<endl;else cout<<"NO"<<endl;
}int main()
{int _;_=1;while(_--){solve();}return 0;
}
9、I-回型矩阵_2024春算法训练3——数组与字符串 (nowcoder.com)
这题用四个while循环代表四个方向,这四个循环终止的条件是撞到边界或者其他已经被填充的数字。代码如下:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;const int N=2010;
int a[N][N];void solve()
{int n;cin>>n;int sum=n*n,cnt=1;int i=1,j=1;a[1][1]=1;while(cnt<sum){while(++j<=n&&!a[i][j])a[i][j]=++cnt;j--;//右while(++i<=n&&!a[i][j])a[i][j]=++cnt;i--;//下while(--j&&!a[i][j])a[i][j]=++cnt;j++;//左while(--i&&!a[i][j])a[i][j]=++cnt;i++;//上}for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){cout<<a[i][j]<<" ";}cout<<endl;}
}int main()
{int _;_=1;while(_--){solve();}return 0;
}
10、J-蛇形矩阵_2024春算法训练3——数组与字符串 (nowcoder.com)
按照canor表划分层数的方式一样,我们将n*n的矩阵分为2*n-1层,每层的元素横纵坐标之和等于层数加一,所以我们只要确定每一层起始或者终止的点的横(纵)坐标即可,我是枚举的纵坐标。记得分奇偶讨论。
代码如下:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;const int N=1010;
int a[N][N];void solve()
{int n;cin>>n;int cnt=1;/*上半段*/for(int i=1;i<=n;i++){int x=i+1;if(i%2==0) for(int j=i;j>=1;j--)a[x-j][j]=cnt++;else for(int j=1;j<=i;j++) a[x-j][j]=cnt++;}//下半段for(int i=n+1;i<=2*n-1;i++){int x=i+1;if(i%2!=0)for(int j=x-n;j<=n;j++)a[x-j][j]=cnt++;else for(int j=n;j>=x-n;j--)a[x-j][j]=cnt++;}for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){cout<<a[i][j]<<" ";}cout<<endl;}}int main()
{int _;_=1;while(_--){solve();}return 0;
}
11、K-[NOIP2006]明明的随机数_2024春算法训练3——数组与字符串 (nowcoder.com)
这题可以利用stl的vector自带的erase函数以及<algorithm>的sort和unique函数或者用数组记录重复出现的数字。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;const int N=200010;
int a[N];void solve()
{ int n;cin>>n;vector<int >ans(n);for(int i=0;i<n;i++)cin>>ans[i];sort(ans.begin(),ans.end());ans.erase(unique(ans.begin(),ans.end()),ans.end());cout<<ans.size()<<endl;for(int i=0;i<ans.size();i++)cout<<ans[i]<<" ";
}int main()
{int _;_=1;while(_--){solve();}return 0;
}
12、L-[NOIP2009]分数线划定_2024春算法训练3——数组与字符串 (nowcoder.com)
按题意排序找到最低分数,然后看有多少人达到了最低分数
#include<iostream>
#include<algorithm>
using namespace std;
const int N=5050;
double rate=1.5;struct infor
{int identity,score;
}queue[N];bool cmp(struct infor a,struct infor b)
{if(a.score!=b.score)return a.score<b.score;else return a.identity>b.identity;
}int main()
{int n,m;cin>>n>>m;for(int i=1;i<=n;i++){int a,b;cin>>a>>b;queue[i]={a,b};}int stan=m*rate;sort(queue+1,queue+1+n,cmp);cout<<queue[n-stan+1].score<<" ";stan=queue[n-stan+1].score;int l=1,r=n;while(l<r){int mid=l+r>>1;if(stan<=queue[mid].score)r=mid;else l=mid+1;}cout<<n-l+1<<endl;for(int i=n;i>=l;i--)cout<<queue[i].identity<<" "<<queue[i].score<<endl;return 0;
}
13、M-[NOIP2007]奖学金_2024春算法训练3——数组与字符串 (nowcoder.com)
这题考察多元素排序,要根据优先级在结构内部定义一个重载符进行运算,注意学号是从大到小排序,代码如下:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;const int N=200010;
int a[N];struct students
{int sum,c,e,m,h;bool operator <(const students &A){if(sum!=A.sum)return sum<A.sum;else if(c!=A.c)return c<A.c;else return h>A.h;}
}s[N];void solve()
{int n;cin>>n;for(int i=1;i<=n;i++){int a,b,c;cin>>a>>b>>c;int d=a+b+c;s[i]={d,a,b,c,i};}sort(s+1,s+1+n);for(int i=n;i>=n-4;i--)cout<<s[i].h<<" "<<s[i].sum<<endl;
}int main()
{int _;_=1;while(_--){solve();}return 0;
}
14、N-[NOIP2003]乒乓球_2024春算法训练3——数组与字符串 (nowcoder.com)
这道题是一道模拟题,但是考察乒乓球的知识(去搜索引擎搜),就是当有一方有11(21)分后他和对手的分差是要大于2的,这是正常的分出胜负的情况,然而还有一种另外特殊情况就是打着打着局数满了,如果此时双方还没有分出胜负也必须强行终止那么最后就不用输出第二次,这种情况用flag特判。如果是因为局数满了而终止的对局,其结果就不需要在最后输出了。输入用getchar() (感觉getchar是真好用) 代码如下:
#include<iostream>
using namespace std;
const int N=10000000;
char result[N];int main()
{int cnt=0;char ch;while((ch=getchar())!='E')if(ch!='\n')result[++cnt]=ch;/*11分制*/int a=0,b=0;bool flag=false;for(int i=1;i<=cnt;i++){if(result[i]=='W')a++;else b++;if(a==11||b==11){while(abs(a-b)<2&&i<=cnt){i++;if(result[i]=='W')a++;else if(result[i]=='L')b++;}if(i>cnt)flag=true;cout<<a<<":"<<b<<endl;a=b=0; }}if(!flag)cout<<a<<":"<<b<<endl;cout<<endl;a=b=0;/*21分制*/flag=false;for(int i=1;i<=cnt;i++){if(result[i]=='W')a++;else b++;if(a==21||b==21){while(abs(a-b)<2&&i<=cnt){i++;if(result[i]=='W')a++;else if(result[i]=='L')b++;}if(i>cnt)flag=true;cout<<a<<":"<<b<<endl;a=b=0;}}if(!flag)cout<<a<<":"<<b<<endl;return 0;
}
15、O-简写单词_2024春算法训练3——数组与字符串 (nowcoder.com)
getchar() yyds!! 一开始设flag为true,因为这里没有特殊说明默认第一个字符为一个字母。遇到第一个或者空格后的第一个字母,输出其大写形式即可。代码如下:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;const int N=200010;
int a[N];void solve()
{char ch;bool f=true;while((ch=getchar())!=EOF){if(ch==' ')f=true;else if(f==true){if(ch>='a'&&ch<='z')ch+='A'-'a';cout<<ch;f=false;}}
}int main()
{int _;_=1;while(_--){solve();}return 0;
}
16、P-[NOIP2008]笨小猴_2024春算法训练3——数组与字符串 (nowcoder.com)
用数组记录所有出现过的字母的次数,排序得到答案,再判断质数(本题认为0不是质数)
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;const int N=200010;
int ha[27];bool isprime(int x)
{if(x==1||x==0)return false;for(int i=2;i<=x/i;i++){if(x%i==0)return false;}return true;
}bool cmp(int a,int b)
{return a<b;
}void solve()
{string a;cin>>a;for(int i=0;i<a.size();i++)ha[a[i]-'a'+1]++;sort(ha+1,ha+27,cmp);int x=1,y=26,w,z;while(!ha[x])x++;w=ha[x];while(!ha[y])y--;z=ha[y];if(isprime(z-w))cout<<"Lucky Word"<<endl<<z-w;else cout<<"No Answer"<<endl<<0;
}int main()
{int _;_=1;while(_--){solve();}return 0;
}
17、Q-[NOIP2000]计算器的改良_2024春算法训练3——数组与字符串 (nowcoder.com)
这题的数据好像与其题目描述的不一样,但是洛谷的原题又没有这个限制:最后一个数据点是真的恶心,程序输出的是-0.00,答案是0.00还不给过。所以这个点需要特判一下。其他的按照思路写就可以,我自己是按照分左右两边分别计算未知数系数和常数写的,好像有点长(能力有限)。推荐去洛谷看一下题解。还是给出我的代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cmath>
#include<map>
using namespace std;
typedef long long ll;
double eps=1e-9;
const int N=200010;
int a[N];void solve()
{string a;cin>>a;char unknown;int mid;;for(int i=0;i<a.size();i++){if(a[i]>='a'&&a[i]<='z')unknown=a[i];if(a[i]=='=')mid=i; }//标准:常数项归到等式右边,带有未知数的项归到等式左边int xi=0,chang=0;//首先讨论等式左边的情况for(int i=mid-1;i>=0;i--){//等号前面要么是带有未知数的多项式要么是常数项if(a[i]==unknown){i--;int ret=0,temp=1;while(a[i]!='+'&&a[i]!='-'&&i>=0){ret+=(a[i]-'0')*temp;i--;temp*=10;}if(ret==0)ret=1;if(i==-1&&a[i]!='+'&&a[i]!='-')xi+=ret;else if(a[i]=='+')xi+=ret;else xi-=ret;}else{int ret=0,temp=1;while(a[i]!='+'&&a[i]!='-'&&i>=0){ret+=(a[i]-'0')*temp;i--;temp*=10;}if(i==-1&&a[i]!='+'&&a[i]!='-')chang-=ret; else if(a[i]=='+')chang-=ret;else chang+=ret;}}/*然后讨论等式右边的情况*/for(int i=a.size()-1;i>=mid+1;i--){/*方程最后一个元素同样只有两种情况要么是带有未知数的想要么是常数项*/if(a[i]==unknown){i--;int ret=0,temp=1;while(a[i]!='+'&&a[i]!='-'&&i>mid){ret+=(a[i]-'0')*temp;i--;temp*=10;}if(ret==0)ret=1;if(i==mid&&a[i]!='+'&&a[i]!='-')xi-=ret;else if(a[i]=='+')xi-=ret;else xi+=ret;}else{int ret=0,temp=1;while(a[i]!='+'&&a[i]!='-'&&i>mid){ret+=(a[i]-'0')*temp;i--;temp*=10;}if(i==mid&&a[i]!='+'&&a[i]!='-')chang+=ret; else if(a[i]=='+')chang+=ret;else chang-=ret;} }double ans=chang*1.0/xi;if(fabs(ans)<eps)ans*=-1;printf("%c=%.3f",unknown,ans);}int main()
{int _;_=1;while(_--){solve();}return 0;
}
18、R-[NOIP2011]统计单词数_2024春算法训练3——数组与字符串 (nowcoder.com)
这题要注意的有几个点:1、所有字母都换成小写
2、记录首次出现的位置(我用的flag判断)
3、用到一个临时字符串存储当前的单词,遇到空格则清空。
#include<iostream>
#include<cstring>
#include<vector>using namespace std;char pa[100000];
int main()
{string mod,p="";cin>>mod; int cnt=0,loc=0,c=0;for(int i=0;i<mod.size();i++)if(mod[i]<'a')mod[i]=mod[i]+'a'-'A';char ch;bool flag=true;getchar();while((ch=getchar())!=EOF){if(ch!=' '){if(ch<'a')ch+='a'-'A';p+=ch;}else{if(p==mod&&flag)cnt++,flag=false;else if(p==mod&&!flag)cnt++;p="";if(flag)loc=c+1;}c++;/*计数*/}if(!cnt)cout<<-1<<endl;else cout<<cnt<<" "<<loc<<endl;return 0;
}
19、S-[NOIP2017]图书管理员_2024春算法训练3——数组与字符串 (nowcoder.com)
开一个辅助数组存放求对应长度后缀所需要的数
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;const int N=200010;
int a[N];int dx[]={1,10,100,1000,10000,100000,1000000,10000000};
struct re
{int len,x;
}b[N];bool cmp(int a,int b)
{return a<b;
}void solve()
{int n,m;cin>>n>>m;for(int i=1;i<=n;i++)cin>>a[i];sort(a+1,a+1+n,cmp);for(int j=1;j<=m;j++)cin>>b[j].len>>b[j].x;for(int i=1;i<=m;i++){bool flag=true;for(int j=1;j<=n;j++){if(a[j]%dx[b[i].len]==b[i].x&&flag)cout<<a[j]<<endl,flag=0;}if(flag)cout<<-1<<endl;}
}int main()
{int _;_=1;while(_--){solve();}return 0;
}
20、T-[NOIP2012]Vigenère 密码_2024春算法训练3——数组与字符串 (nowcoder.com)
首先初始化密码表,然后根据规则去翻译即可。代码如下:
#include<iostream>
#include<cstring>
using namespace std;
const int N=100010;char map[26][26];
char key[110],text[1010];void init()
{for(int i=0;i<26;i++){char base='A'+i;for(int j=0;j<26;j++){char now=base+j;if(now-'A'>=26)now-=26;map[i][j]=now;}}
}int main()
{init();cin>>key>>text;int l=strlen(key),ll=strlen(text);for(int i=0;i<ll;i++){char a=key[i%l];char b=text[i];if(a>='a'&&a<='z')a+='A'-'a';if(b>='a'&&b<='z')b+='A'-'a';char ans;for(int j=0;j<26;j++)if(map[j][a-'A']==b)ans=j+'A';if(text[i]>='a'&&text[i]<='z')ans+='a'-'A';printf("%c",ans);}return 0;
}
这道题好像还有一个比较像的题,可以练一下,这种题是真的折磨人。
链接:潜伏者 (nowcoder.com)