每道题的详细题解已经单发,在此进行汇总。点击链接可以查看详细题解。
目录
第一题:幸运数
满分代码(填空题为不超时代码)
#include <iostream>
using namespace std;
int a[100][10];
int b[100][10];
int main()
{
for(int i=1;i<=9999;i++)
{
int temp=i,sum=0,cnt=0;
while(temp)
{
cnt++;//计算位数
sum+=temp%10;//计算数位和
temp/=10;
}
a[sum][cnt]++;//前一半数字
b[sum][cnt]++;//后一半数字
for(int j=cnt+1;j<=4;j++) b[sum][j]++;//后一半数字首位可以为0
}
int ans=0;
for(int i=1;i<=36;i++)
for(int j=1;j<=4;j++)
ans+=a[i][j]*b[i][j];
cout<<ans;
return 0;
}
第二题:有奖问答
满分代码(填空题为不超时代码)
#include <iostream>
using namespace std;
int k = (1 << 10) - 1;
bool f(int x) {//判断二进制数是否包含连续10个1
bool flag = 1;
while (x) {
if ((k & x) == k){
flag = 0;
break;
}
x = x >> 1;
}
return flag;
}
int main() {
int ans = 0;
for(int j=1;j<=22;j++)//当答题数大于8时,枚举前最多22位
{
if(j<=9){//前面答题少于10题时不可能连续答对10题,这些状态都满足要求
ans+=(1<<j);
continue;
}
for(int i=0;i<=(1<<j)-1;i++)
if(f(i)) ans++;
}
cout << ans+2;//加上总共答7、8题时的两种情况
return 0;
}
第三题:平方数
满分代码:
#include <iostream>
using namespace std;
long long f(long long x) {return x/2+x/4;}
int main() {
long long l, r;
cin >> l >> r;
cout <<f(r) - f(l - 1);
return 0;
}
第四题:更小的数
满分代码:
#include<bits/stdc++.h>
using namespace std;
int p[5005][5005];
int main()
{
string str;
cin>>str;
int ans=0;
for(int i=0;i<str.size();i++)
{
for(int j=i-1;j>=0;j--)
{
if(str[i]<str[j]){
p[j][i]=1;
}
else if(str[i]==str[j]){
p[j][i]=p[j+1][i-1];
}
ans+=p[j][i];
}
}
cout<<ans;
return 0;
}
第五题:颜色平衡树
第六题:买瓜
满分代码:
#include <iostream>
#include<algorithm>
using namespace std;
double a[35];
double b[35];
int n,m;
int ans=35;
void f(int id,double sum,int cut)//当前选择第几个瓜,已拿重量,已劈次数
{
if(sum==m)//拿够了
{
ans=min(ans,cut);
return ;
}
if(id>n) return ;
if(sum>m||cut>ans) return ;
if(sum+b[n]-b[id-1]<m) return ;//剩下的瓜全拿,也不够目标重量
f(id+1,sum,cut);//不拿这个瓜
f(id+1,sum+a[id]/2,cut+1);//切一刀,拿一半
f(id+1,sum+a[id],cut);//不切,全拿
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+n+1,greater<double>());//从大到小排序
for(int i=1;i<=n;i++)
b[i]=a[i]+b[i-1];//前缀和预处理
f(1,0,0);
if(ans<35) cout<<ans;
else cout<<"-1";
return 0;
}
第七题:网络稳定性
满分代码:
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
const int inf=1000010;
int n,m,q;
struct line{//存储边的结构体
int x,y,val;
line(int a,int b,int c){x=a,y=b,val=c;}
};
vector<line>link;//存储输入的所有边
int root[N];//并查集中代表某一元素根(祖先)的数组
bool vis[N];//标志是否遍历过
int dep[N];//深度
int dp[N][20];//动态规划存储第i个节点往前2^j个节点
int val[N][20];//动态规划存储第i个节点到往前2^j个节点中最小的边权值即稳定性
bool cmp(line a,line b) {return a.val>b.val;}
vector<pair<int,int>>node[N];//存储图的邻接链表
int find(int x)//并查集算法
{
if(root[x]==0||root[x]==x) return root[x]=x;
return root[x]=find(root[x]);
}
void fk()//Kruscal算法
{
int cnt=0;
for(int i=0;i<link.size();i++)//在主函数中先将边从大到小排序
{
int x=link[i].x,y=link[i].y;
if(find(x)==find(y)) continue;//边的两点没有连通的话才加入这条边
node[x].push_back(make_pair(y,link[i].val));//将点y加入点x的链表
node[y].push_back(make_pair(x,link[i].val));//将点x加入点y的链表
cnt++;//已加入生成树中边的总数
x=find(x),y=find(y);
root[y]=x;//将x,y两点连通
if(cnt>=n-1) break;//边数超过n-1,生成树已建成
}
}
void dfs(int x)//对x节点进行遍历
{
for(int i=1;(1<<i)<dep[x];i++)//当2^i大于x的深度时结束状态转移
{
dp[x][i]=dp[dp[x][i-1]][i-1];//等于往前2^(i-1)个节点的节点往前2^(i-1)个节点
val[x][i]=min(val[x][i-1],val[dp[x][i-1]][i-1]);
}
for(int i=0;i<node[x].size();i++)//遍历所有子节点
{
int t=node[x][i].first;
if(vis[t]) continue;
vis[t]=1;//标志为已遍历
dep[t]=dep[x]+1;//子节点深度+1
dp[t][0]=x;//子节点的父节点表示为x
val[t][0]=node[x][i].second;//子节点往前1个节点中最小边权值为与父节点相连的边权值
dfs(t);//遍历子节点
}
}
int lca(int x,int y)//求x和y的最近公共祖先lca
{
int ans=inf;//设置稳定性ans的初始值
if(dep[x]<dep[y]) swap(x,y);//令x节点为较深的节点
int k=log2(dep[x]-dep[y]);//移动步幅的最大值
for(int i=k;i>=0;i--)//将x向上移动
{
if(dep[dp[x][i]]>=dep[y])//x移动2^j步后深度仍然不浅与y
{
ans=min(ans,val[x][i]);
x=dp[x][i];
}
}//移动后x与y深度相同
if(x==y) return ans;//y是x的祖先
k=log2(dep[x]);//移动步幅的最大值
for(int i=k;i>=0;i--)
{
if(dp[x][i]==dp[y][i]) continue;//移动2^i步后是x和y的祖先,跳过
ans=min(ans,val[x][i]);
ans=min(ans,val[y][i]);//移动2^i步后更新稳定性
x=dp[x][i];
y=dp[y][i];//移动x和y
}//移动后x和y的上一个节点是lca
ans=min(ans,val[x][0]);
ans=min(ans,val[y][0]);//比较最后两条边,x和y到lca的边权值
return ans;
}
int main()
{
cin>>n>>m>>q;
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
link.push_back(line(x,y,z));
}
sort(link.begin(),link.end(),cmp);//从大到小排序所有边
fk();//kruscal建立最大生成树
for(int i=1;i<=n;i++)
{
if(vis[i]) continue;
vis[i]=1;
dep[i]=1;//根节点深度为1
dfs(i);//动态规划求lca
}
for(int i=1;i<=q;i++)
{
int x,y;
cin>>x>>y;
if(find(x)!=find(y)) cout<<"-1"<<endl;//并查集检查是否两点是否连通
else cout<<lca(x,y)<<endl;//lca算法求稳定性
}
return 0;
}
第八题:异或和之和
满分代码:
#include <iostream>
using namespace std;
long long a[200005];
long long sum[200005];
int main() {
int n;
cin >> n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]^a[i];
long long ans = 0;
for(int k=0;k<=20;k++)//枚举每一对异或和的二进制第k位
{
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
long long temp=((sum[j]^sum[i-1])>>k)&1;//位运算取1个数字的第k位数字
ans+=temp*(1<<k);//结果加上这一对异或和的第k位乘以2^k
}
}
}
cout << ans;
return 0;
}
第九题:像素放置
满分代码:
#include<bits/stdc++.h>
using namespace std;
int Map[15][15];//方格的颜色
vector<int> limit[15][15];//方格影响到的数字方格
struct num_p{//表示数字方格的结构体
int sum;//周围九宫格的黑色总数
int x,y;//数字方格的坐标
int lastX,lastY;//该数字方格影响的最后一个方格坐标
num_p(int a,int b,int c){sum=a;x=b;y=c;}
};
vector<num_p> nums;//存放所有数字方格的数组
int n,m;
bool ans=0;//是否找到答案
bool islast(int id,int x,int y)//判断某一坐标是不是数字方格影响的最后一个方格
{
return (x==nums[id].lastX&&y==nums[id].lastY);
}
void dfs(int x,int y)//将编号为x的方格涂成y颜色
{
if(ans) return ;//已经找到答案 不再继续执行
int tx=x/m,ty=x%m;//将编号转为坐标
Map[tx][ty]=y;//将方格涂色
if(y)
{
for(auto it=limit[tx][ty].begin();it!=limit[tx][ty].end();it++)
nums[*it].sum--;//如果涂成黑色,将影响到的所有数字减一
}
for(auto it=limit[tx][ty].begin();it!=limit[tx][ty].end();it++)
{
if(nums[*it].sum<0) return ;//有数字被减到小于0
if(islast(*it,tx,ty)&&nums[*it].sum>0) return ;//有数字没有被减到0
}
if(x>=n*m-1)//枚举到了最后一个
{
ans=1;
return ;
}
dfs(x+1,0);//将下一号涂成白色
dfs(x+1,1);//将下一号涂成黑色
tx=(x+1)/m,ty=(x+1)%m;
for(auto it=limit[tx][ty].begin();it!=limit[tx][ty].end();it++)
nums[*it].sum++;//撤销将下一号涂成黑色产生的影响
}
int main()
{
cin>>n>>m;
char c;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cin>>c;
if(c<='9'&&c>='0') nums.push_back(num_p(c-'0',i,j));//将数字方格存起来
}
}
for(auto it=nums.begin();it!=nums.end();it++)
{
for(int i=it->x-1;i<=it->x+1;i++)
{
for(int j=it->y-1;j<=it->y+1;j++)
{
if(i<0||i>=n||j<0||j>=m) continue;
it->lastX=i,it->lastY=j;//找到数字方格影响的最后一个方格
limit[i][j].push_back(int(it-nums.begin()));//坐标i,j受到本数字方格影响
}
}
}
dfs(0,0);//将0号方格涂成白色
dfs(0,1);//将0号方格涂成黑色
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
cout<<Map[i][j];
cout<<endl;
}
return 0;
}
第十题:翻转硬币
2023第14届蓝桥杯大赛软件赛省赛C/C++大学A组第10题题解:翻转硬币-CSDN博客
满分代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e7;
long long ans=0,n;
bool vis[N];
vector<int> prime;//存储质数的容器
int f_mu[N],sum_mu[N];//莫比乌斯函数的值,莫比乌斯函数的前缀和
unordered_map<int,int> sum_mu_long;//莫比乌斯函数的前缀和,当n超过数组的存储范围时用map存储
void findprime()//寻找质数,主要是计算莫比乌斯函数的值和前缀和
{
f_mu[1]=1;
sum_mu[1]=1;//设定u(1)的初始值和前缀和
for(int i=2;i<=n&&i<N;i++)
{
if(vis[i]==0)//未被筛过
{
prime.push_back(i);//存入质数
f_mu[i]=-1;//质数的莫比乌斯函数为1
}
for(int j=0;j<prime.size()&&i*prime[j]<=n&&i*prime[j]<N;j++)//遍历质数
{
vis[i*prime[j]]=1;//标记为合数
if(i%prime[j]==0)
{
f_mu[i*prime[j]]=0;//包含平方因子
break;
}
f_mu[i*prime[j]]=-f_mu[i];//不包含平方因子,质因子个数奇偶性改变
}
sum_mu[i]=f_mu[i]+sum_mu[i-1];//前缀和递推
}
}
int SumMu(int x)//求莫比乌斯函数的前缀和
{
if(x<N) return sum_mu[x];
if(sum_mu_long.count(x)) return sum_mu_long[x];
int sum=1;
for(long long l=2,r;l<=x;l=r+1)
{
r=x/(x/l);//整除分块
sum-=SumMu(x/l)*(r-l+1);//杜教筛的递推公式
}
return sum_mu_long[x]=sum;
}
int main()
{
cin>>n;
findprime();
for(long long l=1,r;l*l<=n;l=r+1)
{
r=sqrt(n/(n/(l*l)));//整除分块
ans+=(SumMu(r)-SumMu(l-1))*(n/(l*l));
}
cout<<ans;
return 0;
}