----------------------------2019年省赛A组C++--------------------------------- A、平方和 小明对数位中含有 2、0、1、9 的数字很感兴趣,在 1 到 40 中这样的数包括 1、2、9、10 至 32、39 和 40,共 28 个,他们的和是 574,平方和是 14362。请问,在 1 到 2019 中,所有这样的数的平方和是多少? 思路: bool函数判断是否含有2019,主函数求平方和即可。 代码:
typedef long long ll;
bool have(ll x){
if (x==0) return true;
ll num=x%10;
while (num>2 && num<9){ //不含有2019则看下一位
x/=10;
num=x%10;
}
if (x!=0) return true;
return false;
}
int main(){
ll sum=0;
for (ll i=1;i<2020;i++){
if (have(i)) sum+=i*i;
}
cout<<sum;
return 0;
}
B、数列求值 给定数列 1, 1, 1, 3, 5, 9, 17, …,从第 4 项开始,每项都是前 3 项的和。求第 20190324 项的最后 4 位数字。 思路: 初始化长度为3的数组,每次求和时mod 10000(只要最后4位),直到第20190324项。 代码:
int main(){
int store[3]={1,1,1};
//只需要存储三位的数组,模10000
for (int i=4;i<20190325;i++){
store[i%3]=(store[0]+store[1]+store[2])%10000;
}
cout<<store[20190324%3]<<endl;
return 0;
}
C、最大降雨量 49 张法术符分别写着1至49,法术共持续 7 周,每天小明都要使用一张法术符,法术符不能重复使 用。每周小明施展法术产生的能量为这周 7 张法术符上数字的中位数。7 周后求雨将成功,降雨量为 7 周能量的中位数。请问最大值是多少? 思路: 使得每周的中位数最大即可,例如第一周选49 48 47 46 3 2 1则中位数为46;第二周选45 44 43 42 6 5 4则中位数为42;第三周选41 40 39 38 9 8 7则中位数为38;第四周选37 36 35 34 12 11 10则中位数为34…最终中位数为第四周中位数34。
D、迷宫: 1为障碍 0 为可通行,入口左上角出口右下角。 010000 000100 001001 110000 对于上面的迷宫,从入口开始可以按DRRURRDDDR 通过,一共 10 步。其中 D、U、L、R 分别表示向下、向上、向左、向右走。 对于下面这个更复杂的迷宫(30 行 50 列),请找出一种通过迷宫的方式, 其使用的步数最少,在步数最少的前提下,请找出字典序最小的一个作为答案。请注意在字典序中D<L<R<U。 01010101001011001001010110010110100100001000101010 00001000100000101010010000100000001001100110100101 01111011010010001000001101001011100011000000010000 01000000001010100011010000101000001010101011001011 00011111000000101000010010100010100000101100000000 11001000110101000010101100011010011010101011110111 00011011010101001001001010000001000101001110000000 10100000101000100110101010111110011000010000111010 00111000001010100001100010000001000101001100001001 11000110100001110010001001010101010101010001101000 00010000100100000101001010101110100010101010000101 11100100101001001000010000010101010100100100010100 00000010000000101011001111010001100000101010100011 10101010011100001000011000010110011110110100001000 10101010100001101010100101000010100000111011101001 10000000101100010000101100101101001011100000000100 10101001000000010100100001000100000100011110101001 00101001010101101001010100011010101101110000110101 11001010000100001100000010100101000001000111000010 00001000110000110101101000000100101001001000011101 10100101000101000000001110110010110101101010100001 00101000010000110101010000100010001001000100010101 10100001000110010001000010101001010101011111010010 00000100101000000110010100101001000001000000000010 11010000001001110111001001000011101001011011101000 00000110100010001000100000001000011101000000110011 10101000101000100010001111100010101001010000001000 10000010100101001010110000000100101010001011101000 00111100001000010000000110111000000001000000001011 10000001100111010111010001000110111010101101111000 思路: 用node结构体记录走过路径及步数,bfs寻找最小步数及最小字典序路径。 代码:
#include<queue>
int n=30,m=50,visit[30][50];
struct Node{int x,y,step;string str;};
char maze[30][50];
string in="010101010010110010010101100101101001000010001010100000100010000010101001000010000000100110011010010101111011010010001000001101001011100011000000010000010000000010101000110100001010000010101010110010110001111100000010100001001010001010000010110000000011001000110101000010101100011010011010101011110111000110110101010010010010100000010001010011100000001010000010100010011010101011111001100001000011101000111000001010100001100010000001000101001100001001110001101000011100100010010101010101010100011010000001000010010000010100101010111010001010101000010111100100101001001000010000010101010100100100010100000000100000001010110011110100011000001010101000111010101001110000100001100001011001111011010000100010101010100001101010100101000010100000111011101001100000001011000100001011001011010010111000000001001010100100000001010010000100010000010001111010100100101001010101101001010100011010101101110000110101110010100001000011000000101001010000010001110000100000100011000011010110100000010010100100100001110110100101000101000000001110110010110101101010100001001010000100001101010100001000100010010001000101011010000100011001000100001010100101010101111101001000000100101000000110010100101001000001000000000010110100000010011101110010010000111010010110111010000000011010001000100010000000100001110100000011001110101000101000100010001111100010101001010000001000100000101001010010101100000001001010100010111010000011110000100001000000011011100000000100000000101110000001100111010111010001000110111010101101111000";
//按字典序存储方向
int X[4]={1,0,0,-1},Y[4]={0,-1,1,0};
string dir="DLRU",road;
void init(){
for(int i=0;i<n;i++){
for(int j=0;j<m;j++) visit[i][j]=0;
}
visit[0][0]=1;
}
//点的合法性
bool legal(int x,int y){
if(x<0 || x>=n || y<0 || y>=m) return false;
return true;
}
//广度搜索
void bfs(){
//初始化
queue<Node> store;
Node sta={0,0,0,""};
store.push(sta);
int mini=100000000;
init();//初始化经过
while(!store.empty()){
Node t=store.front();
if(t.x==n-1&&t.y==m-1){//到达终点
if(t.step<mini){
mini=t.step;
road=t.str;
}
if(t.step==mini && t.str<road) road=t.str; //最小字典序
}
else{
for(int i=0;i<4;i++){
int nowx = t.x+X[i] , nowy = t.y+Y[i];
if(legal(nowx,nowy) && !visit[nowx][nowy] && maze[nowx][nowy]=='0'){
Node temp={nowx,nowy,t.step+1,t.str+dir[i]};
store.push(temp);
visit[nowx][nowy]=1;
}
}
}
store.pop();//弹出队头元素
}
cout<<road;
}
int main(){
int cnt=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++) maze[i][j]=in[cnt++];
}
bfs();
return 0;
}
E、RSA解密
F、完全二叉树的权值 给定一棵包含 N 个节点的完全二叉树,树上每个节点都有一个权值,按从上到下、从左到右的顺序依次是 A1, A2, · · · AN,如下图所示: 现在小明要把相同深度的节点的权值加在一起,他想知道哪个深度的节点权值之和最大?如果有多个深度的权值和同为最大,请你输出其中最小的深度。注:根的深度是 1。 【样例输入】 7 1 6 5 4 3 2 1 【样例输出】 2 思路: 边输入边累加,当到达下一层时比较权值和,更新maxi depth为最大权值和和对应最小深度。 代码:
typedef long long ll;
int main(){
ll n,in,mi=1,num=1,maxi=0,t=0,depth=0,cnt=1;
cin>>n;
for (ll i=0;i<n;i++){
cin>>in;
if (i<num) t+=in;
else{
//找最大权值和
if (maxi<t){
maxi=t;
depth=cnt;
}
t=in; //重新计算最大权值和
mi*=2; num+=mi; //节点个数分裂
cnt+=1;
}
}
//最深层别忘记判断
if (maxi<t){
maxi=t;
depth=cnt;
}
cout<<depth;
return 0;
}
G:外卖店优先级 “饱了么”外卖系统中维护着 N 家外卖店,编号 1 ~ N。每家外卖店都有一个优先级,初始时 (0 时刻) 为 0。每经过 1 个时间单位,若外卖店没有订单则优先级会减 1,最低减到0;若有订单则每有一单优先级加 2。 若某时刻优先级大于5,店铺被系统加入优先缓存中;若优先级小于等于3,则被清除出优先缓存。 给定 T 时刻以内的 M 条订单信息,请你计算 T 时刻时有多少外卖店在优先缓存中。 【样例输入】 2 6 6 1 1 5 2 3 1 6 2 2 1 6 2 【样例输出】 1 思路: 将订单信息按照先时间后店铺升序的方式排序,初始化1个优先级序列res[]和1个是否在缓冲队列join[],每个时刻维护1个map来存放该店铺有几个订单,并实时更新优先级序列和缓冲队列。 代码:
#include <algorithm>
#include <cmath>
#include <map>
#define maxn 100001
struct node{int time,num;};
node in[maxn]; //输入
int res[maxn],join[maxn];//存储优先级和缓冲队列
//订单排序
bool cmp(node a,node b){
if (a.time==b.time) return (a.num<b.num);
return (a.time<b.time);
}
int main(){
int n,m,t,j=1,k=0,cnt=0;
cin>>n>>m>>t;
//矩阵初始化
for (int i=0;i<m;i++) cin>>in[i].time>>in[i].num;
for (int i=1;i<=n;i++){
res[i]=0; //存储值
join[i]=0; //非优先队列
}
//按时间先后、num大小排序
sort(in,in+m,cmp);
map<int,int> have; //存储每个单位有外卖的店家
while (k<m && j<=t){
while(in[k].time==j){
if (have.find(in[k].num)==have.end()) have[in[k].num]=1; //有1单
else have[in[k].num]+=1; //不只有1单
k+=1;
}
for (int i=1;i<=n;i++){
if (have.find(i)==have.end()){
res[i]=max(res[i]-1,0);//最少是0
if (join[i] && res[i]<4){
join[i]=0; //清出队列
cnt-=1;
}
}
else{
res[i]+=2*have[i];
if (!join[i] && res[i]>5){
join[i]=1; //加入队列
cnt+=1;
}
}
}
have.clear();
j+=1; //下个时刻
}
cout<<cnt;
return 0;
}
H、修改数组 长度为 N 的数组 A = [A1, A2, · · · AN],有可能有重复出现的整数。现在小明要按以下方法将其修改为没有重复整数的数组: 当修改Ai时,检查Ai是否在A1~Ai?1中出现过。若出现过则给 Ai 加1;若新的Ai仍在之前出现过,持续给Ai加1。给定初始的 A 数组,请你计算出最终的A数组。 【样例输入】 5 2 1 1 3 4 【样例输出】 2 1 3 4 5 思路: 暴力循环为O(n^2/2)复杂度,没时间的话捞分用 。 巧妙地利用并查集:初始化i的父亲为i,依次遍历输入的数组,使a[i] = getf(a[i]),再令f(a[i]) = f(a[i]+1)即可。 并查集思路copy自CSDN大佬 改写代码如下:
#define maxn 1000001
int f[maxn],in[maxn];
//并集找根
int father(int x){
if (f[x]==x) return x;
return f[x]=father(f[x]);
}
int main(){
int n; cin>>n;
for (int i=1;i<=n;i++) f[i]=i;//初始化根节点
for (int i=1;i<=n;i++){
cin>>in[i];
in[i] = father(in[i]);
f[in[i]] = father(in[i]+1); //该数字已用,将根+1
cout<<in[i]<<" ";
}
return 0;
}
I 糖果 糖果店的老板一共有 M 种口味的糖果出售,编号 1 ~ M,老板将糖果K 颗一包整包出售。小明希望能品尝到所有口味的糖果,给定 N 包糖果,计算小明最少买几包,就可以品尝到所有口味的糖果。 【样例输入】 6 5 3 (N M K) 1 1 2 1 2 3 1 1 3 2 3 5 5 4 2 5 1 2 【样例输出】 2
J、组合数问题 【输入格式】 第一行两个数 t, k,其中 t 代表该测试点包含 t 组询问,k 的意思与上文中相同。接下来 t 行每行两个整数 n, m,表示一组询问。 【输出格式】 输出 t 行,每行一个整数表示对应的答案。由于答案可能很大,请输出答案除以 109 + 7 的余数。 【样例输入】 1 2 3 3 【样例输出】 1 【样例说明】 在所有可能的情况中,只有 C1 2 = 2 是 2 的倍数。 【样例输入】 2 5 4 5 6 7 【样例输出】 0 7 【样例输入】 3 23 23333333 23333333 233333333 233333333 2333333333 2333333333 【样例输出】 851883128 959557926 680723120
|