十四届
A 子2023
#include<bits/stdc++.h>
using namespace std;
long long a[10000], tot = 0, ans = 0;
int main()
{
long long dp[4]={0};//分别代表"2"、"20"、"202"、"2023"的数量
for (int i = 1; i <= 9; i++){
a[++tot] = i;
}
for (int i = 10; i <= 99; i++){
a[++tot] = i / 10;
a[++tot] = i % 10;
}
for (int i = 100; i <= 999; i++){
a[++tot] = i / 100;
a[++tot] = i / 10 % 10;
a[++tot] = i % 10;
}
for (int i = 1000; i <= 2023; i++){
a[++tot] = i / 1000;
a[++tot] = i / 100 % 10;
a[++tot] = i / 10 % 10;
a[++tot] = i % 10;
}
for(int i=1;i<=tot;i++)
{
if(a[i]==2){
dp[0]++;
dp[2]+=dp[1];
}else if(a[i]==0){
dp[1]+=dp[0];
}else if(a[i]==3){
dp[3]+=dp[2];
}
}
cout<<dp[3]<<endl;
return 0;
}
B 双子数
#include <iostream>
using namespace std;
const int N = 1e7 + 10;
bool st[N];
long long res = 0;
long long prime[N], cnt;
void get_prime(int n)
{
for(int i = 2; i <= n; i++)
{
if(!st[i])
{
prime[cnt++] = i;
}
for(int j = 0; prime[j] <= n/i; j++)
{
st[prime[j] * i] = true;
if(i % prime[j] == 0)
{
break;
}
}
}
}
int main()
{
long long l = 2333, r = 23333333333333;
get_prime(1e7);
for(int i = 0; i < cnt; i++)
{
if(prime[i]*prime[i]*prime[i+1]*prime[i+1] > 23333333333333)
{
break;
}
for(int j = i + 1; j < cnt; j++)
{
if(prime[i]*prime[i]*prime[j]*prime[j] < 2333)
{
continue;
}
if(prime[i]*prime[i]*prime[j]*prime[j] > 23333333333333)
{
break;
}
res++;
}
}
cout << res << endl;
return 0;
}
C班级活动
#include <bits/stdc++.h>
using namespace std;
int n,t,s1=0,s2=0;int a[100005]={0};
int main(){
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>t;
a[t]++;
}
for(int i=1;i<=n;i++)
{
if(a[i]==1)
{
s1+=1;
}
else if(a[i]>2)
{
s2+=a[i]-2;
}
}
cout<<s2+max(s1-s2,0)/2<<endl;
return 0;
}
D合并数列
#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main(){
int n,m;
deque<int> q1,q2;
cin>>n>>m;
for(int i=0;i<n;i++){
int a;
cin>>a;
q1.push_back(a);
}
for(int i=0;i<m;i++){
int a;
cin>>a;
q2.push_back(a);
}
int ans=0;//记录答案
while(!q1.empty()){
if(q1.front()==q2.front()){//相等直接出队
q1.pop_front();
q2.pop_front();
}else if(q1.front()>q2.front()){//q2小就合并q2前面两个
q2[1]+=q2[0];
q2.pop_front();
ans++;//合并次数+1
}else{//q1小就合并q1前面两个
q1[1]+=q1[0];
q1.pop_front();
ans++;//合并次数+1
}
}
cout<<ans<<endl;
}
E数三角
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=2e3+4;
ll x[N],y[N];
set<pair<ll,ll>>s;
int dis(int i,int j)
{
return (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
}
void solve()
{
int n;cin>>n;
//set用来存题目给的坐标,便于后面查找对称点
for(int i=1;i<=n;++i)
{
cin>>x[i]>>y[i];
s.insert({x[i],y[i]});
}
ll ans=0;
//用map来存到除掉中心点,剩余点到中心点的距离为d的点的个数
map<ll,ll>mp;
for(int i=1;i<=n;++i)
{
ll cnt=0;//记录每一轮对称点的个数
for(int j=1;j<=n;++j)
{
if(i!=j)//除掉中心点
{
ll d=dis(i,j);//计算到中心点的距离
ans+=mp[d];//计算完距离后,看原先到中心点的距离为d有多少个,就可以组成多少个等腰三角形,加到答案中
mp[d]++;//然后再更新到中心点的距离为d的点个数
//中点坐标公式,计算对称点
int xx=2*x[i]-x[j];
int yy=2*y[i]-y[j];
//用set集合,记录题目给的坐标点 是否有我们计算出来的对称的点
//有:说明此时三个点共线,记录一下,再最后减去
if(s.count({xx,yy}))cnt++;
}
}
//除二:因为三点共线的会被记录2次,分别是除点中心点的点被枚举到时候记录的
ans-=cnt/2;
mp.clear();//定完一个中心点就要清楚一下,进入下一次枚举,保证下一次枚举数据正确
}
cout<<ans;
}
int main(){
int t=1;
while(t--)
{
solve();
}
return 0;
}
F
G AB路线 BFS
https://blog.csdn.net/m0_57487901/article/details/135844658
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 1000000007;
const int N = 1010;
int n, m, k;
bool st[N][N][11];
int dx[] = {0, 1, 0, -1};
int dy[] = {-1, 0, 1, 0};
int main()
{
ios_base ::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> k;
vector<string> s(n);
for (int i = 0; i < n; ++i)
{
cin >> s[i];
}
queue<array<int, 3>> q;
q.push({0, 0, 1});
st[0][0][1] = true;
int ans = 0;
while (q.size())
{
int size = q.size();
while (size--)
{
auto p = q.front();
q.pop();
int x = p[0], y = p[1];
if (x == n - 1 && y == m - 1)
{
cout << ans << '\n';
return 0;
}
if (p[2] == k)
{
for (int i = 0; i < 4; ++i)
{
int a = x + dx[i], b = y + dy[i];
if (a >= 0 && a < n && b >= 0 && b < m && s[a][b] != s[x][y] && !st[a][b][1])
{
//够K个了 如 现在是'A',以后该弄'B'了 不同的
st[a][b][1] = true;
q.push({a, b, 1});
}
}
}
else
{
for (int i = 0; i < 4; ++i)
{
int a = x + dx[i], b = y + dy[i];
if (a >= 0 && a < n && b >= 0 && b < m && s[a][b] == s[x][y] && !st[a][b][p[2] + 1])
{
//次数p[i]++还没弄过
//不够K个,A还是A
st[a][b][p[2] + 1] = true;//次数P[2]++
q.push({a, b, p[2] + 1});
}
}
}
}
ans++;
}
cout << -1 << '\n';
return 0;
}
H抓娃娃 前缀和+差分
https://www.luogu.com.cn/problem/solution/P9426
//https://www.luogu.com.cn/problem/solution/P9426
#include <bits/stdc++.h>
using namespace std;
const int N=2e6+5;
int n,m;
int mp[N];
int main()
{
cin>>n>>m;
int l,r;
for (int i=1;i<=n;i++)
{
cin>>l>>r;
mp[l+r]++;//标记中点
}
for (int i=1;i<N;i++)
{
mp[i]+=mp[i-1];//前缀和预处理
}
for (int i=1;i<=m;i++)
{
cin>>l>>r;
l*=2;
r*=2;
cout<<mp[r]-mp[l-1]<<endl;
}
return 0;
}
I
J
十三届
1 2022 背包问题
第十三届蓝桥杯c++b组国赛题解(还在持续更新中...) - 回忆、少年 - 博客园 (cnblogs.com)
#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
const int N=2500;
//dp[i][j][k]表示从前i件物品中选,每件物品的价值等于其编号,且当前选了j件物品,且当前价值为k的所有选法数
int dp[N][15][N];
signed main(){
//因为价值k为0,所以只有一种选法:就是啥也不选
for(int i=0;i<N;i++)dp[i][0][0]=1;
for(int i=1;i<=2022;i++){
for(int j=1;j<=10;j++){
for(int k=1;k<=2022;k++){
//不选第i个物品
dp[i][j][k]=dp[i-1][j][k];
//选第i个物品
if(k>=i)dp[i][j][k]+=dp[i-1][j-1][k-i];
}
}
}
cout<<dp[2022][10][2022]<<endl;
return 0;
}
2 钟表
2022年十三届蓝桥杯国赛(C/C++大学B组)个人题解_蓝桥杯国赛题目-CSDN博客
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
double md, fd, sd;
for (double m = 0; m < 60; m++)
{
md = 360 * m / 60;
for (double f = 0; f < 60; f++)
{
fd = 360 * f / 60 +6 * m / 60;
for (double s = 0; s <= 6; s++)
{
sd = 360 * s / 12 + 30 * (f * 60 + m) / 3600;
double A = fabs(fd - sd);
A = min(A, 360 - A);
double B = fabs(fd - md);
B = min(B, 360 - B);
if (A == 2 * B)
{
cout << s << " " << f << " " << m << endl;
}
}
}
}
return 0;
}
3 卡牌 二分
第十三届蓝桥杯c++b组国赛题解(还在持续更新中...) - 回忆、少年 - 博客园 (cnblogs.com)
必须long long
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=2e5+5;
ll a[N],b[N];
ll n,m;
ll check(ll x)
{
ll temp=0;
for(ll i=0;i<n;i++){
//如果当前第i种卡牌已经满足条件,则第i种卡牌不需要消耗空白卡牌
if(x<=a[i])continue;
//如果当前第i种卡牌就算用上所有能够手写第i种卡牌的空白卡牌仍然不满足条件,则直接返回false
if(x>a[i]+b[i])return 0;
//否则统计当前用了多少张空白卡牌来手写第i种卡牌
temp+=x-a[i];
}
//如果使用的空白卡牌数超过了题目中提供的空白卡牌数m,则直接返回false
if(temp>m)return 0;
//否则表示满足,返回true
else return 1;
}
int main()
{
cin>>n>>m;
for(ll i=0;i<n;i++)cin>>a[i];
for(ll i=0;i<n;i++)cin>>b[i];
ll l=0,r=2e5+5;
while(l<r)
{
int mid=l+r+1>>1;
//如果当前套牌数满足条件,继续加大套牌数
if(check(mid))l=mid;
else r=mid-1;
}
cout<<l<<endl;
return 0;
}
4最大数字 dfs
#include<iostream>
#include<algorithm>
using namespace std;
string s,ans;
int a,b;
void dfs(int idx,int a,int b){
//如果已经遍历完了整个数字的每一位,则更新最大值,并返回
if(idx>s.size()){
ans=max(ans,s);
return;
}
//当前数位通过减法操作变成9所需要的操作次数t
int t=s[idx]-'0'+1;
//如果当前拥有的减法操作次数大于上述操作次数t,则将当前位变成9
if(b>=t){
//保留现场
int temp=s[idx]-'0';
//将当前位变成9
s[idx]='9';
//递归操作下一位,当前拥有的减法操作次数减少t次
dfs(idx+1,a,b-t);
//恢复现场
s[idx]=temp+'0';
}
//当前数位x通过加法操作变成[x+1,9]所需要的操作次数t1
int t1=min(9-(s[idx]-'0'),a);
如果当前拥有的加法操作次数大于上述操作次数t1,则使用加法操作修改当前位
if(a>=t1){
//保留现场
int temp=s[idx];
//修改当前位
s[idx]=s[idx]+t1;
//递归操作下一位,当前拥有的加法操作次数减少t1次
dfs(idx+1,a-t1,b);
//恢复现场
s[idx]=temp;
}
}
int main(){
cin>>s>>a>>b;
dfs(0,a,b);
cout<<ans<<endl;
return 0;
}
5 出差
dijstka求最短路
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
#define int long long
typedef pair<int,int>PII;
const int N=1e5+5,M=2*N;
int h[N],e[M],ne[M],w[M],a[N],dist[N],vis[N],idx;
void add(int x,int y,int z){
e[idx]=y,w[idx]=z,ne[idx]=h[x],h[x]=idx++;
}
void dijkstra(){
memset(dist,0x3f,sizeof dist);
priority_queue<PII,vector<PII>,greater<PII> >q;
q.push({0,1});
dist[1]=0;
while(q.size()){
int dis=q.top().first;
int s=q.top().second;
q.pop();
if(vis[s])continue;
vis[s]=1;
for(int i=h[s];~i;i=ne[i]){
int j=e[i];
if(dist[j]>dis+w[i]){
dist[j]=dis+w[i];
q.push({dist[j],j});
}
}
}
}
signed main(){
memset(h,-1,sizeof h);
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
while(m--){
int x,y,z;
cin>>x>>y>>z;
add(x,y,z+a[y]);
add(y,x,z+a[x]);
}
dijkstra();
cout<<dist[n]-a[n]<<endl;
return 0;
}
F 费用报销 DP
第十三届蓝桥杯c++b组国赛题解(还在持续更新中...) - 回忆、少年 - 博客园 (cnblogs.com)
#include<iostream>
#include<algorithm>
using namespace std;
const int N=5005;
//记录每月的天数
int month[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
//dp[i]表示从第1天到第i天范围内的票据中选择的最大报销金额
int dp[N];
int main(){
int n,m,k;
//前缀和求本年到当前月总共多少天
for(int i=1;i<=13;i++)month[i]+=month[i-1];
cin>>n>>m>>k;
while(n--){
int x,y,z;
cin>>x>>y>>z;
//month[x-1]+y表示x月y号距离本年初共多少天
dp[month[x-1]+y]=max(dp[month[x-1]+y],z);
}
//从第一天枚举到本年最后一天
for(int i=1;i<=month[13];i++){
//如果第i天的票据加上距离第i天前k天的票据的价值不超过m,则说明可以选择第i天的票据
//取选择第i天的票据dp[i]+dp[max((int)0,i-k)]和不选择第i天的票据dp[i-1]的最大值
if(dp[i]+dp[max((int)0,i-k)]<=m)dp[i]=max(dp[i-1],dp[i]+dp[max((int)0,i-k)]);
//如果第i天的票据不能选择,那么dp[i]直接就是dp[i-1]了
else dp[i]=dp[i-1];
}
cout<<dp[month[13]]<<endl;
return 0;
}
G
H LCA算法
I 齿轮 思维
第十三届蓝桥杯c++b组国赛题解(还在持续更新中...) - 回忆、少年 - 博客园 (cnblogs.com)
#include<iostream>
#include<algorithm>
using namespace std;
const int N=2e5+5;
int mp[N],vis[N],a[N];
int main(){
int n,m,flag=0;
cin>>n>>m;
for(int i=0;i<n;i++){
cin>>a[i];
//如果数组中遇到了相同的数,那么倍数1是满足条件的,标记一下
if(vis[a[i]])flag=1;
//标记数组的每一个数,以便后续判断
vis[a[i]]=1;
}
//如果数组长度为1或者1被标记过了,则倍数1是满足条件的
if(flag||n==1)mp[1]=1;
//遍历数组的每个数a[i]
for(int i=0;i<n;i++){
//遍历数组每个数的倍数
for(int j=2;j*a[i]<=N;j++){
//如果a[i]*j被标记过, 那么倍数j是满足条件的,标记一下
if(vis[j*a[i]])mp[j]=1;
}
}
while(m--){
int x;
cin>>x;
//如果倍数x被标记过,直接输出YES
if(mp[x])cout<<"YES"<<endl;
//否则输出NO
else cout<<"NO"<<endl;
}
return 0;
}
J 搬砖 背包
2022年第十三届蓝桥杯大赛软件类国赛C/C++大学B组题解 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/626446047
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXX = 1e3 + 7;
struct node
{
int w, v;
} nod[MAXX];
int cmp(node a, node b)
{
return a.v + a.w < b.v + b.w;
}
int dp[20007];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
for (int i = 1; i <= n; ++i)
cin >> nod[i].w >> nod[i].v;
sort(nod + 1, nod + n + 1, cmp);
for (int i = 1; i <= n; ++i)
for (int j = 20020; j >= nod[i].w; --j)
if (nod[i].v >= j - nod[i].w)
dp[j] = max(dp[j], dp[j - nod[i].w] + nod[i].v);
int ans = 0;
for (int i = 0; i <= 20020; ++i)
ans = max(ans, dp[i]);
cout << ans;
return 0;
}
十二届
题目+解析:
2021第十二届蓝桥杯国赛C/C++大学B组题解_蓝桥杯异或三角-CSDN博客https://blog.csdn.net/qq_44758960/article/details/117596428
B
#include "bits/stdc++.h"
using namespace std;
bool solve(int n){
while(n){
int temp = n%10;
if(temp==0||temp==1||temp==4||temp==6||temp==8||temp==9)
return false;
n/=10;
}
return true;
}
//埃氏筛法
int maxn = 20210605;
bool p[20210605] = {false};
int main(){
for(int i=2;i<=maxn;i++){
if(!p[i]){
for(int j = 2*i ;j<=maxn;j+=i){
p[j] = true;
}
}
}
int cnt = 0;
for(int i=2;i<=maxn;i++){
if(!p[i]&&solve(i))
cnt++;
}
cout<<cnt;
}
C
/**977**/
#include <bits/stdc++.h>
using namespace std;
int f[100];
bool Run(int year){
if( (year%4==0 && year%100!=0) || (year%400==0) ){
return true;
}
return false;
}
bool check(int y,int m,int d){
int sum=0;
while(y>0){
sum+=y%10;
y/=10;
}
while(m>0){
sum+=m%10;
m/=10;
}
while(d>0){
sum+=d%10;
d/=10;
}
if(f[sum]==1){
return true;
}
return false;
}
void init(){
f[1]=1;
for(int i=2;i*i<=100;i++){ //100: 各个数字相加挺小的
f[i*i]=1;
}
}
int main(){
//从2001.1.1到2021.12.31 // 平年2月 28天 闰年29天
init();
int ans=0;
for(int i=2001;i<=2021;i++){//year
int m[13]={0,//m
31,//1
28,//2
31,//3
30,//4
31,//5
30,//6
31,//7
31,//8
30,//9
31,//10
30,//11
31//12
};
if(Run(i)){//如果是闰年
m[2]++;
}
for(int j=1;j<=12;j++){//month
for(int k=1;k<=m[j];k++){
if(check(i,j,k)){
// cout<<"年"<<i<<"月"<<j<<"日"<<k<<endl;
ans++;
}
}
}
}
cout<<ans<<endl;
return 0;
}
D
i-i-j>=0 -> j<=i-1
(2021年第十二届蓝桥杯国赛)D:最小权值(动态规划)-CSDN博客https://blog.csdn.net/AC__dream/article/details/124617309
F
G 有规律->降低时间
蓝桥杯2021年第十二届国赛真题-异或变换-CSDN博客https://blog.csdn.net/weixin_54562114/article/details/124706621
H 数位DP !思考
题目:
小蓝最近在学习二进制。他想知道 1 到 N 中有多少个数满足其二进制表示中恰好有 K 个 1
。你能帮助他吗?
对于所有评测用例, 1≤𝑁≤10^18,1≤𝐾≤50
求某数 二进制表示中 有几个1 ->模板
但是时间复杂度很大,不行
题解:
#include <iostream>
#define int long long
using namespace std;
long long C(long long b, long long a) // 计算组合(b在下面,a在上面)
{
long long sum = 1;
for (long long i = b, j = 1; j <= a; i--, j++)
sum = sum * i / j;
return sum;
}
signed main()
{
int n, k;
cin >> n >> k;
int cnt = 0, ans = 0;
if (n == k && k == 1)
{
ans = 1;
cout << ans;
return 0;
}
for (int i = 62; i >= 1; --i)//移动i,有i+1位
//10^18<<2^64 最多63位 最多移63-1=62位
//2的63次方:9223372036854775808
//2的64次方:18446744073709551616(>10^18)(不行)
{
if (k - cnt + 1 == 0)//均选,,>0个1
break;
if ((1ll << i) & n)//移几位,后面就有几个1
{
cnt++;
if (i >= k - cnt + 1)
ans += C(i, k - cnt + 1);
}
}
if (cnt == k)//看n本身满不满足 1个数k
ans++;
cout << ans;
return 0;
}
I
J
十一届
ABCDEG
2020第十一届蓝桥杯C++国赛B组真题和题H解 (11.14决赛)_试题 b: 扩散-CSDN博客
B BFS/模拟
#include <iostream>
#include <queue>
using namespace std;
#define Max_N 10005
#define ADD 2021
typedef pair<int, int> P;//记录点的坐标
int map[Max_N][Max_N] = {0};//保存这个点的时间,并且利用是不是-1判断有没有访问过这个点
long long ans = 4;//扩展出的点的个数
int dx[5] = {0, 0, 1, -1};
int dy[5] = {-1, 1, 0, 0};
int main() {
memset(map, -1, sizeof(map)); // map设置为-1代表没有访问过。map存放的值是:时间
queue<P> Que;//标准的BFS模板
Que.push(P(0 + ADD, 0 + ADD));//这里将坐标从边缘往中间移动
map[0 + ADD][0 + ADD] = 0;
Que.push(P(2020 + ADD, 11 + ADD));
map[2020 + ADD][11 + ADD] = 0;
Que.push(P(11 + ADD, 14 + ADD));
map[11 + ADD][14 + ADD] = 0;
Que.push(P(2000 + ADD, 2000 + ADD));
map[2000 + ADD][2000 + ADD] = 0;
while (!Que.empty()) {
int ix = Que.front().first, iy = Que.front().second;
Que.pop();
if (map[ix][iy] == 2020) {//如果这个点的时间已经是2020,就不从这个点继续扩展。
continue;
}
for (int ddt = 0; ddt < 4; ddt++) {//朝着四个方向扩展
int tx = ix + dx[ddt], ty = iy + dy[ddt];
if (map[tx][ty] == -1) {
Que.push(P(tx, ty));
map[tx][ty] = map[ix][iy] + 1;
ans++;
}
}
}
cout << ans << endl;
return 0;
}
法二: 用这个!!!!
2020蓝桥杯大赛总决赛B组C语言-试题B:扩散_哔哩哔哩_bilibili
C
#include<iostream>
using namespace std;
int flag[105];
int main()
{
int i;
for (int i = 2; i <= 100; i++)
{
int tmp = i;
for (int j = 2; j <= tmp; j++)
{
while (tmp % j == 0)
{
tmp /= j;
flag[j]++;
}
}
}
long long ans = 1;
for (int i = 1; i <= 100; i++)
{
ans *= flag[i] + 1;
}
cout << ans;
}
D
本质上升序列(蓝桥杯2020国赛) - acmloser - 博客园 (cnblogs.com)
H
#include<iostream>
#include<algorithm>
using namespace std;
long long sum=0;
struct Student{
long long si;//进门的时间
long long ai;//答疑的时间
long long ei;//出门的时间
long long zi;//总时间
long long di;//进门和答疑的时间和
}a[1010];//结构体数组取大10
bool cmp(Student a,Student b)//排序的方式
{
if(a.zi!=b.zi) return a.zi<b.zi;//若两个结构体的总时间不等,则从小到大排序
else return a.di<b.di;//反之则只比较进门和答疑的时间和
}
int main()
{
long long n,p=0;
cin>>n;
for(long long i=0;i<n;i++)
{
cin>>a[i].si>>a[i].ai>>a[i].ei;//读入数据
a[i].zi=a[i].si+a[i].ai+a[i].ei;//计算总时间
a[i].di=a[i].si+a[i].ai;//计算进门与答疑的时间
}
sort(a,a+n,cmp);//对结构体进行排序
for(long long i=0;i<n;i++)
{
sum+=p+a[i].si+a[i].ai;//让总时间等于学生进门时间加上答疑的时间再加上之前学生的总时间
p+=a[i].zi;//定义了一个longlong变量来计算到此为止之前学生所花的时间
}
cout<<sum<<endl;
return 0;
}
2020蓝桥杯决赛C/C++组 答疑(编程大题)_c++ [蓝桥杯 2020 国 abc] 答疑-CSDN博客
题目考点就是结构体排序,要注意的也就是时刻的相加,额外定义了一个变量p来计算截至目前的时刻,再让sum+=p和学生进门与答疑的时间就好了
排序的话得先考虑学生花费的总时间,如果总时间相等再考虑学生进门和答疑的时间差距。
第十届
A、B
2019 第十届蓝桥杯大赛软件赛决赛,国赛,C/C++大学B组题解-阿里云开发者社区 (aliyun.com)
C
2019 第十届蓝桥杯大赛软件赛决赛,国赛,C/C++大学B组题解-阿里云开发者社区 (aliyun.com)
D
2019 第十届蓝桥杯大赛软件赛决赛,国赛,C/C++大学B组题解-阿里云开发者社区 (aliyun.com)
E
strp=2时,一定是重合着走
第十届蓝桥杯(国赛)——路径计数_蓝桥杯路径计数-CSDN博客
#include <iostream>
using namespace std;
int ans, step;
bool st[10][10];
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
void dfs(int x, int y, int step)
{
if(step > 12) return;
if(x == 1 && y == 1 && st[x][y] && step > 2)
{
ans ++;
return;
}
for (int i = 0; i < 4; i ++)
{
int a = x + dx[i], b = y + dy[i];
if(a < 1 || a > 5 || b < 1 || b > 5 || st[a][b]) continue;
st[a][b] = true;
dfs(a, b, step + 1);
st[a][b] = false;
}
}
int main()
{
dfs(1, 1, 0);
cout << ans << endl;
return 0;
}
F DP
2019 第十届蓝桥杯大赛软件赛决赛,国赛,C/C++大学B组题解-阿里云开发者社区 (aliyun.com)
第九届
D 搭积木
可以把这一系列的点视为一个图中的散点,这样你的任务就变成了在一个有限集合内,去求出遍历完这所有点所需要的最小步数,反正点也不多,总会全部进队列的,也总会结束BFS的。
利用广度优先搜索了(寻找最小步骤)
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int MAX=100005;
int dp[MAX];
int n,k;
void bfs()
{
queue<int> q;
q.push(0);
dp[0]=0;
while(!q.empty())
{
int p=q.front();
q.pop();
if(dp[(p+1)%n]==-1) //下一点若未走则记录步数并入队列
{
dp[(p+1)%n]=dp[p]+1;
q.push((p+1)%n);
}
if(dp[(p+k)%n]==-1) //下k点若未走则记录步数并入队列
{
dp[(p+k)%n]=dp[p]+1;
q.push((p+k)%n);
}
}
}
int main()
{
memset(dp,-1,sizeof(dp)); //包含于cstring中,这里必须全设为-1,不能为0
cin>>n>>k;
bfs();
int ans=dp[0];
for(int i=1;i<n;i++) ans=ans>dp[i]?ans:dp[i];
cout<<ans<<endl;
return 0;
}
后两题不会
第八届
A
#include <bits/stdc++.h>
using namespace std;
int main()
{
long a = ('M'-'A'+10)*pow(36,3);
long b = ('A'-'A'+10)*pow(36,2);
long c = ('N'-'A'+10)*pow(36,1);
long d = ('Y'-'A'+10)*pow(36,0);
long res = a+b+c+d;
printf("%ld\n",res);
return 0;
}
B 瓷砖样式 dfs
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define maxn 3
#define maxm 10
int a[maxn][maxm];
int ans;
bool check()
{
for(int i = 0; i < maxn-1; i++)
for(int j = 0; j < maxm-1; j++)
{
int p = a[i][j];
if(p == -1) return false; //地板必须全部铺满
if(p == a[i+1][j] && p == a[i][j+1] && p == a[i+1][j+1]) return false;
//任意2*2格子不能为同一种颜色
}
return true;
}
void dfs(int cur)
{
if(cur == maxn * maxm) //已到头
{
if(check())
{
ans++;
}
return;
}
//计算出
int x = (cur - 1) / maxm; //下标从0开始
int y = cur - x * maxm - 1;
if(a[x][y] != -1)dfs(cur + 1);//格子已经铺了
//横着铺
if(y + 1 < maxm && a[x][y] == -1 && a[x][y + 1] == -1)
{
a[x][y] = a[x][y + 1] = 0;//铺黄色
dfs(cur + 1);
a[x][y] = a[x][y + 1] = 1;//铺橙色
dfs(cur + 1);
a[x][y] = a[x][y + 1] = -1; //还原回溯
}
//竖着铺
if(x + 1 < maxn && a[x][y] == -1 && a[x + 1][y] == -1)
{
a[x][y] = a[x + 1][y] = 0;
dfs(cur + 1);
a[x][y] = a[x + 1][y] = 1;
dfs(cur + 1);
a[x][y] = a[x + 1][y] = -1;
}
}
int main()
{
memset(a,-1,sizeof(a));
ans = 0;
dfs(1);
cout<<ans<<endl;
return 0;
}
C 发现环
无环图:有拓扑序列 至少有一个入度为0的点
入度为0的点入队,while 队头t,删掉边t->j(t的限制满足要求),但j入度减少了,为同样--
if(d[j]==0) j入队
若有环:队列中无点 (队列中入度为0)
类似于拓补排序。
首先可以将无向图转化为有向图,即将对于每条无向边变换为双向建边,就好处理了。
在这种情况下,很显然当一个点的入度大于或等于 2 时,即有不止一条边连向这个点时,该点就在环上。
我们可以建一个布尔类型 𝑣𝑖𝑠 数组来标记这个点的入度是否等于 1,那么这个点就不在环上,那么没有被标记的点就是我们要求的答案了。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1;
int n;
int in[N];
vector<int>e[N];
bool vis[N];//标记入度是否为1,即该点是否在环上
void topo()//拓补排序
{
queue<int>q;
for(int i=1;i<=n;i++)
if(in[i]==1)//标记入度为1的点
{
q.push(i);
vis[i]=true;
}
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=0;i<e[u].size();i++)
{
int v=e[u][i];
in[v]--;
if(in[v]==1)//标记入度为1的点
{
q.push(v);
vis[v]=true;
}
}
}
}
void print()//输出未标记的点
{
for(int i=1;i<=n;i++)
if(!vis[i])cout<<i<<' ';
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);//双向建边
in[u]++;
in[v]++;//两点的入度都增加
}
topo();
print();
return 0;
}
D对局匹配 !!
法一:
先分组,再动态规划。
-
根据数字对 𝑘k 取模的值的不同分成 𝑘k 组,因为对 𝑘k 取模为 00 的数的下一个可能相差为 𝑘k 的数只可能是对 𝑘k 取模同样为 00 的。
-
动态规划是对每个组内的元素进行动态规划,算出每个组内的最大值。
#include<iostream>
#include<cstring>
using namespace std;
int num[1000010];
int count[1000011];//记录数出现的次数
int dp[1000011];
int max(int a,int b)
{
return (a>b)?a:b;
}
int main()
{
int N,K,i,value,res=0,j,sum=0;
cin >> N >> K;
memset(num,0,sizeof(num));
memset(count,0,sizeof(count));
for(i=0;i<N;i++)
{
cin >> value;
num[value]++;//记录各个数出现的次数
}
if(K==0)
{
for(i=0;i<N;i++)
{
if(num[i])
res++;
}
}
else
{
for(i=0;i<K;i++)//记录首项为0-K-1的等差数列 ,共K个 遍历 组 一组一组搞
{
sum=0; //一组里几个元素
for(j=i;j<=1000010;j+=K)//等差数列
{
count[sum++]=num[j]; //count[i]到i几个可能ans
}
dp[0]=count[0];
dp[1]=max(dp[0],count[1]);
for(j=2;j<sum;j++)
{
dp[j]=max(dp[j-1],dp[j-2]+count[j]);//状态转移方程,选择前一个,那么后面这个就不能选,或者隔一个数选择
//加上这个数的个数
}
res+=dp[sum-1];//加上这个等差数列(以i为首项)情况下的结果
}
}
cout << res<<endl;
return 0;
}
法二:
显然的贪心。
如果 𝑘=0k=0,直接统计有多少个不同个数即可,因为但凡选一个相同的都不满足。
否则,贪心地解决问题,过程如下:
-
若 𝑖i 的个数比 𝑖+𝑘i+k 的个数小,直接更新 𝑖+𝑘i+k 的个数,让它减去 𝑖i 的个数。
-
否则,让 𝑖+𝑘i+k 的个数设为 00,因为它已经被匹配得干干净净了。
最后统计所有 00 到 100000−𝑘100000−k 的个数之和就是答案。(只统计较小的,因为较大的被拿去匹配了)
由于该方法每次总是拿小的去匹配大的,因此不会重复。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int p[N];
int main()
{
int n, k;
cin >> n >> k;
for(int i = 1;i <= n;i++)
{
int t;
cin >> t;
p[t]++; //计数
}
if(!k)
{
int ans = 0;
for(int i = 0;i <= 100000;i++) ans += (p[i] ? 1 : 0); //统计不同的数的个数
cout << ans << endl;
}
else
{
int ans = 0;
for(int i = 0;i <= 100000 - k;i++)
{
if(p[i])
{
if(p[i] < p[i + k]) //如果小
{
p[i + k] -= p[i];
}
else
{
p[i + k] = 0;
}
}
}
for(int i = 0;i <= 100000 - k;i++) //统计剩余的
{
ans += p[i];
}
cout << ans << endl;
}
return 0;
}
第七届
A 一步之遥
#include<bits/stdc++.h>
using namespace std;
int main()
{
int x, y;
int ans = 99999;
for(x = 1; x <= 330; x++)
{
for(y = 1; y <= 330; y++)
{
if(x * 97 - 127 * y == 1)
{
ans = min(ans, x + y);
}
}
}
cout << ans<< endl;
return 0;
}
B凑平方数
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int a[10]= {0,1,2,3,4,5,6,7,8,9};
ll ans;
bool judge(ll n)
{
return sqrt(n)==(ll)(sqrt(n));
}
//x记录上个数大小,i记录当前位数
void dfs(ll x,int i)
{
if(i==10)
{
ans++;
return;
}
if(a[i]==0)
{
if(i==0)
dfs(0,i+1);
return;
}
ll sum=0;
for(int j=i; j<10; j++)
{
sum=(sum*10+a[j]);
if(judge(sum)&&sum>x)
dfs(sum,j+1);
}
}
int main()
{
do
{
dfs(-1,0);
}
while(next_permutation(a,a+10));
cout<<ans<<endl;
return 0;
}
D机器人塔 !
二进制枚举,枚举最底下一行的排列状态。最底下一行的排列状态确定后,上面的排列状态也就确定了,所以,只要统计构建的人塔中A和B的数量是否与输入相同,相同的话种类数+1。
什么是二进制枚举?以本题为例,每一个位置要么放A要么放B,这和二进制有点像啊,那就让A对应1,B对应0。
这样一来,1 1 0什么意思?A A B的意思吧。加入最底下一行有3个人,所有的可能,BBB,BBA,BAB,BAA,ABB,ABA,AAB,AAA,对应的二进制为,000,001,010,011,100,101,110,111,这不就是2^3吗。所以,最后一行的排列状态就可以通过循环表现出来了, for(int i=0;i<=(1<<3)-1;i++)
#include<bits/stdc++.h>
using namespace std;
const int N=50;
int dp[N];//用一维数组表示二维状态,有点类似01背包问题优化的思想,但不是01背包!
int main(){
int n,m,ans=0;
cin>>m>>n;
// int h=(int)sqrt(2*(m+n));//行数
int h;
for (int i=0;i<=30;i++)//i:计算行数
{
if (i*(i+1)/2==m+n)
{
h=i;
break;
}
}
for(int num=0;num<=(1<<h)-1;num++) //枚举最底层那行的h种数
{
int tmp_h=h,tmp=num,cnt_a=0,cnt_b=0;
//对每一个数:计算二进制
for(int i=tmp_h;i>=1;i--,tmp>>=1)
{
dp[i]=tmp&1;//初始化最底下一行
if(dp[i]) cnt_a++;
else cnt_b++;
}
while(tmp_h--) //h-- 向上推导每一行
{
for(int i=1;i<=tmp_h;i++) //某一行看看
{
if(dp[i+1] == dp[i]) cnt_a++,dp[i]=1;//相等数上面set A i++下一行比这一行大1,已经进去过的数字
else cnt_b++,dp[i]=0;//set B
}
}
if(cnt_a==m && cnt_b==n) ans++; //底层为,,,的情况符合要求
}
cout<<ans<<endl;
}
第六届校内选拔
pow(x,x)
如果x的x次幂结果为10(参见下图),你能计算出x的近似值吗?
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
double ans;
double minn=10.0;
for(double i=2.000001;i<=2.999999;i+=0.000001)
{
double result=pow(i,i);
if(fabs(result-10.0) <minn)
{
ans=i;
minn=fabs(result-10.0);
}
}
printf("%lf\n",ans);
return 0;
}
2 DFS
题目:
今有7对数字:两个1,两个2,两个3,…两个7,把它们排成一行。
要求,两个1间有1个其它数字,两个2间有2个其它数字,以此类推,两个7之间有7个其它数字。如下就是一个符合要求的排列:
17126425374635
当然,如果把它倒过来,也是符合要求的。
请你找出另一种符合要求的排列法,并且这个排列法是以74开头的。
注意:只填写这个14位的整数,不能填写任何多余的内容,比如说明注释等。
解题思路
这个题目是要我们从多种排列中找到一个符合要求的排列,那么我们应该怎么去做呢?这种题型都可以采用回溯法来进行搜索,因为在回溯的过程中我们可以一直利用条件来进行判断并逐渐向正确结果靠拢。 我们可以开设两个辅助数组来进行记录判断,v i s visvis数组我们可以用来判断这个数字是否已经被确定,即两个位置是否都已放置,a r r arrarr数组我们可以用来记录i ii在a r r [ i ] arr[i]arr[i]这个位置上。通过这个,我们设置好起始出发位置和终止位置,由于题目一开始就已经确定了7 , 4 7,47,4是在第一个和第二个位置,所以我们起始位置是第3 33个,这也代表着前两个位置已经确定了,那么最终位置我们自然也可以知道即是第15 1515个,因为这代表着前14 1414个位置已经确定了,也就是最终结果找到了。在回溯过程中,我们在对可设置点的状态进行递归后要还原此点的状态,避免干扰。
#include<iostream>
#include<cstring>
using namespace std;
bool vis[100010];
int arr[100010];
void fun(int index)
{
if(index==15)
{
for(int i=1;i<=14;i++)
cout<<arr[i];
cout<<endl;
exit(0);//停止 return不行
}
for(int i=1;i<=7;i++)//试数字
{
if(arr[index]) fun(index+1);//弄下一个位置
if(index+i+1<=14&&!vis[i]&&!arr[index]&&!arr[index+i+1])//<=14
{
vis[i]=true;
arr[index]=arr[index+i+1]=i;
fun(index+1);
vis[i]=false;
arr[index]=arr[index+i+1]=0;
}
}
}
int main()
{
memset(vis,false,sizeof vis);
memset(arr,0,sizeof arr);
arr[1]=arr[9]=7;
arr[2]=arr[7]=4;
vis[7]=true;
vis[4]=true;
fun(3);
return 0;
}
勾股定理
西方称为毕达哥拉斯定理,它所对应的三角形现在称为:直角三角形。
已知直角三角形的斜边是某个整数,并且要求另外两条边也必须是整数。
求满足这个条件的不同直角三角形的个数。
输入格式
输入一个整数 n (0<n<10000000) 表示直角三角形斜边的长度。
输出格式
要求输出一个整数,表示满足条件的直角三角形个数。
答案O(n)
/*
*blog:https://blog.csdn.net/hzf0701
*邮箱:unique_powerhouse@qq.com
*注:文章若有任何问题请私信我或评论区留言,谢谢支持。
*/
#include<bits/stdc++.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
using namespace std;
typedef long long ll;
const int maxn=1e5;//数组所开最大值
const int mod=1e9+7;//模
const int inf=0x3f3f3f3f;//无穷大
ll n;
void solve(){
ll ans=0;
ll temp=n*n;
for(ll i=1;;i++){
ll j=sqrt(temp-i*i);
//为了防止重复,当i>j的时候退出。
if(i>j){
break;
}
if(i*i+j*j==temp){
ans++;
}
}
cout<<ans<<endl;
}
int main(){
while(cin>>n){
solve();
}
return 0;
}
数独 DFS
题目:你一定听说过“数独”游戏。
如图,玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个同色九宫内的数字均含1-9,不重复。
数独的答案都是唯一的,所以,多个解也称为无解。
本图的数字据说是芬兰数学家花了3个月的时间设计出来的较难的题目。但对会使用计算机编程的你来说,恐怕易如反掌了。
本题的要求就是输入数独题目,程序输出数独的唯一解。我们保证所有已知数据的格式都是合法的,并且题目有唯一的解。
输入格式
输入9行,每行9个数字,0代表未知,其它数字为已知。
输出格式
输出9行,每行9个数字表示数独的解。
样例输入
005300000
800000020
070010500
400005300
010070006
003200080
060500009
004000030
000009700
样例输出
145327698
839654127
672918543
496185372
218473956
753296481
367542819
984761235
521839764
解析:首先对于数独来说,它的每一行每一列以及同色九宫格都是1~9的排列,那么,我们可以根据这个条件不断、去搜索试错,直到找到符合要求的解法。 我们可以将这个数独划分为9 × 9 9\times 99×9的矩阵,然后我们按行从左往右开始dfs搜索,这样的话,假设我们搜索到了( x , y ) (x,y)(x,y)这个位置,那么说明在之前的都已经确定好了数。故我们很容易就清楚起始搜索点是( 0 , 0 ) (0,0)(0,0),终止搜索点是( 8 , 8 ) (8,8)(8,8)。而我们如何判断呢?主要是对于那些值未知的点,我们要将1 11~9 99的数都代入,同时模拟继续dfs后要还原状态,必须保证各种搜索路径之间不互相干扰。
/*
*blog:https://blog.csdn.net/hzf0701
*邮箱:unique_powerhouse@qq.com
*注:文章若有任何问题请私信我或评论区留言,谢谢支持。
*/
#include<bits/stdc++.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
using namespace std;
typedef long long ll;
const int maxn=1e5;//数组所开最大值
const int mod=1e9+7;//模
const int inf=0x3f3f3f3f;//无穷大
string num[9];
bool check(int x,int y,int value){
//先判断同行同列是否有相同的值。
rep(i,0,8){
if(num[x][i]-'0'==value)
return false;
if(num[i][y]-'0'==value)
return false;
}
//还需判断同色九宫格是否满足条件。
//获取边界坐标。
int temp_x=x/3*3;//获取行。
int temp_y=y/3*3;//获取列。
rep(i,temp_x,temp_x+2){
rep(j,temp_y,temp_y+2){
if(num[i][j]-'0'==value)
return false;
}
}
return true;
}
//接下来开始dfs搜索。我们要知道,若点上不为0,说明已经确定了。
void dfs(int x,int y){
//我们搜索按行从左到右,所以我们从(0,0)开始,到达(9,0)的时候说明前面的都已经确定了,即数独已完成。
if(x>8){
//已经完成,直接打印。
rep(i,0,8){
cout<<num[i]<<endl;
}
cout<<endl;
return;
}
//判断该点是否已经确定。
if(num[x][y]!='0'){
dfs(x+(y+1)/9,(y+1)%9);//这里注意理解,考虑到坐标变化进位。
}
else{
//我们就需要对这个点从1~9赋值尝试。
rep(i,1,9){
if(check(x,y,i)){
num[x][y]='0'+i;
dfs(x+(y+1)/9,(y+1)%9);
//变为0,恢复状态。
num[x][y]='0';
}
}
}
}
void solve(){
dfs(0,0);
}
int main(){
rep(i,0,8){
cin>>num[i];
}
solve();
return 0;
}
5 树形dp
题目:
G将军有一支训练有素的军队,这个军队除开G将军外,每名士兵都有一个直接上级(可能是其他士兵,也可能是G将军)。
现在G将军将接受一个特别的任务,需要派遣一部分士兵(至少一个)组成一个敢死队,
为了增加敢死队队员的独立性,要求如果一名士兵在敢死队中,
他的直接上级不能在敢死队中。
请问,G将军有多少种派出敢死队的方法。注意,G将军也可以作为一个士兵进入敢死队。
输入格式:
输入的第一行包含一个整数n,表示包括G将军在内的军队的人数。军队的士兵从1至n编号,G将军编号为1。
接下来n-1个数,分别表示编号为2, 3, …, n的士兵的直接上级编号,编号i的士兵的直接上级的编号小于i。
输出格式:
输出一个整数,表示派出敢死队的方案数。由于数目可能很大,你只需要输出这个数除10007的余数即可。
输入样例:
3
1 1
样例输出1
4
样例说明
这四种方式分别是:
选1;
选2;
选3;
选2, 3。
样例输入2
7
1 1 2 2 3 3
样例输出2
40
解析: 感觉同没有上司的舞会
当前节点A,当前节点的子节点B
A被选中的次数=A被选中的次数*B不被选中的次数。//当前节点选中,其子节点不能被选。
A不被选中的次数=A不被选中的次数*(B被选中的次数+B不被选中的次数)。//A节点不被选中,其子节点可以被选也可以不被选。
得到最终的总数=根节点被选中次数+根节点不被选中次数-1。//减一是减去全部都不选,队伍里没有一人的情况。
递归
#include <bits/stdc++.h>
using namespace std;
const int N = 100010,mod = 10007;
int n;
int h[N],e[N],ne[N],idx;
int f[N][2];
void add(int a,int b)
{
e[idx] = b,ne[idx] = h[a],h[a] = idx ++;
}
void dfs(int u)
{
f[u][0] = f[u][1] = 1;
for(int i = h[u];i != -1;i = ne[i])
{
int j = e[i];
dfs(j);
f[u][1] = (f[u][1] * f[j][0]) % mod;
f[u][0] = (f[u][0] * (f[j][0] + f[j][1])) % mod;
}
}
int main()
{
cin >> n;
memset(h,-1,sizeof h);
for(int i = 1;i < n;i ++)
{
int x;
cin >> x;
add(x,i + 1);
}
dfs(1);
cout << (f[1][0] + f[1][1] - 1) % mod;
return 0;
}//没找到地方评测不确定是否是AC的代码
第六届
积分之谜
小明开了个网上商店,卖风铃。共有3个品牌:A,B,C。
为了促销,每件商品都会返固定的积分。
小明开业第一天收到了三笔订单:
第一笔:3个A + 7个B + 1个C,共返积分:315
第二笔:4个A + 10个B + 1个C,共返积分:420
第三笔:A + B + C,共返积分…
你能算出第三笔订单需要返积分多少吗?
请提交该整数,不要填写任何多余的内容。
#include <iostream>
using namespace std;
int main(){
/*
3*A+7*B+1*C=315
4*A+10*B+1*C=420
? A+B+C=? ?
*/
for(int A=1;A<316;A++){
for(int B=1;B<316;B++){
for(int C=1;C<316;C++){
if((3*A+7*B+1*C==315)&&(4*A+10*B+1*C==420))
cout<<"A="<<A<<" B="<<B<<" C="<<C<<" A+B+C="<<A+B+C<<endl;
}
}
}
return 0;
}.51cto.com/u_14691718/3329725
完美正方形
如下边长的22个正方形
2 3 4 6 7 8 12 13 14 15 16 17 18 21 22 23 24 26 27 28 50 60
紧贴着上边沿的是从左到右依次为:47 46 61,
你能计算出紧贴着下边沿的是哪几个正方形吗?
#include <bits/stdc++.h>
using namespace std;
int a[] = {0,2,5,9,11,16,17,19,21,22,24,26,30,31,33,35,36,41,46,47,50,52,61};
int len,mp[201][201];
bool book[101];
bool Judge(int x,int y,int num)
{
if(x+num-1 > len || y+num-1 > len)
return false;
for(int i=x;i<x+num;i++)
for(int j=y;j<y+num;j++)
if(mp[i][j])
return false;
return true;
}
void color(int x,int y,int num)
{
int l;
if(num == 0) {
book[mp[x][y]] = false;
l = mp[x][y];
}
else {
book[num] = true;
l = num;
}
for(int i=x;i<x+l;i++)
for(int j=y;j<y+l;j++)
mp[i][j] = num;
}
bool flag;
void dfs(int x,int y)
{
if(x == len+1) {
flag = true;
return ;
}
if(mp[x][y]) {
if(y == len)
dfs(x+1,1);
else
dfs(x,y+1);
return;
}
for(int i=1;i<=22;i++) {
if(book[a[i]])
continue;
if(!Judge(x,y,a[i]))
break; //a[i]随着i增大而增大,因此没必要在试下去
color(x,y,a[i]);
if(y == len)
dfs(x+1,1);
else
dfs(x,y+1);
if(flag)
return;
color(x,y,0);
}
}
int main()
{
len = 47+46+61;
flag = false;
memset(mp,0,sizeof mp);
memset(book,false,sizeof book);
color(1,1,47);
color(1,1+47,46);
color(1,1+47+46,61);
dfs(1,1);
int colorr=-1;
for(int i=1;i<=len;i++) {
if(mp[len][i] != colorr) {
colorr = mp[len][i];
printf("%d ",colorr);
}
}
return 0;
}
密文搜索
福尔摩斯从 X 星收到一份资料,全部是小写字母组成。
他的助手提供了另一份资料:许多长度为 8 的密码列表。
福尔摩斯发现,这些密码是被打乱后隐藏在先前那份资料中的。
请你编写一个程序,从第一份资料中搜索可能隐藏密码的位置。要考虑密码的所有排列可能性。
输入格式
输入第一行:一个字符串 s,全部由小写字母组成,长度小于 1024*1024
紧接着一行是一个整数 n,表示以下有 n 行密码,1 ≤ n ≤1000
紧接着是 n 行字符串,都是小写字母组成,长度都为 8
输出格式
一个整数, 表示每行密码的所有排列在 s 中匹配次数的总和。
样例输入
aaaabbbbaabbcccc
2
aaaabbbb
abcabccc
样例输出
4
解释
第一个密码匹配了3次,第二个密码匹配了1次,一共4次。
题解:在s里连续存放(某位置)
#include <bits/stdc++.h>
using namespace std;
map<string, int> k;
int main()
{
string s, ss;
int n, ans = 0;
cin >> s;
cin >> n;
for(register int i = 1; i <= n; i++)
{
cin >> ss;
sort(ss.begin(), ss.end());//将ss中的字母从小到大排序
k[ss]++;
}
for(register int i =0 ; i < s.size() - 7; i++)
{
ss = s.substr(i, 8);//取s中的连续8位
sort(ss.begin(),ss.end());
ans += k[ss];
}
cout << ans << endl;
return 0;
}
后两题太难
另外
出自这篇博客
蓝桥杯第六届蓝桥杯大赛个人赛校内选拔(软件类)C++A组,B组,C组真题解析-CSDN博客
形如:1/a 的分数称为单位分数。可以把1分解为若干个互不相同的单位分数之和。
例如:
1 = 1/2 + 1/3 + 1/9 + 1/18
1 = 1/2 + 1/3 + 1/10 + 1/15
1 = 1/3 + 1/5 + 1/7 + 1/9 + 1/11 + 1/15 + 1/35 + 1/45 + 1/231
等等,类似这样的分解无穷无尽。
我们增加一个约束条件:最大的分母必须不超过30
请你求出分解为n项时的所有不同分解法。
数据格式要求:
输入一个整数n,表示要分解为n项(n<12)
输出分解后的单位分数项,中间用一个空格分开。
每种分解法占用一行,行间的顺序按照分母从小到大排序。
例如,
输入:
4
程序应该输出:
1/2 1/3 1/8 1/24
1/2 1/3 1/9 1/18
1/2 1/3 1/10 1/15
1/2 1/4 1/5 1/20
1/2 1/4 1/6 1/12
再例如,
输入:
5
程序应该输出:
1/2 1/3 1/12 1/21 1/28
1/2 1/4 1/6 1/21 1/28
1/2 1/4 1/7 1/14 1/28
1/2 1/4 1/8 1/12 1/24
1/2 1/4 1/9 1/12 1/18
1/2 1/4 1/10 1/12 1/15
1/2 1/5 1/6 1/12 1/20
1/3 1/4 1/5 1/6 1/20
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 2000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
解题思路
首先,这道题本身其实是有问题的,因为并没有明确条件,以及分母是否可以为负。同时对一些无解的n nn,也没有加以排除。抛开这些,这道题还是比较好的,比较创新,也不像那种模板题。回归正题,我们来看,我们要寻找n nn个分数,它们的和为1 11(分数不相同)。所以这实际上是一道抽象的搜索题。我们采用dfs进行搜索,对于此题来说,如果我们找到了一个分数就将其存入数组(由于分数的分子都为1 11,故我们只需存取分母,当然我们在计算的时候也要保证分数是最简形式)。 最重要就是我们要找到初始状态和终止状态,由于我们是寻找n nn个分数,故我们易知初始状态为1 11,终止状态为n nn。这个状态表示的是我们正在寻找的分数。为了避免重复杂乱,所以我们搜索分数的分母也是从小到大,同样,我们也要时刻记录每个状态剩余的值。所以我们实现的dfs有四个参数。 具体看代码,附有详细解释。
/*
*blog:https://blog.csdn.net/hzf0701
*邮箱:unique_powerhouse@qq.com
*注:文章若有任何问题请私信我或评论区留言,谢谢支持。
*/
#include<bits/stdc++.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
using namespace std;
typedef long long ll;
const int maxn=1e5;//数组所开最大值
const int mod=1e9+7;//模
const int inf=0x3f3f3f3f;//无穷大
int n,a[31];//n表示需要分解的分数,a[i]表示第i个分数的分母。
//gcd,便于分母之间相加运算,约分。
int gcd(int n,int m){
int temp;
while(n%m){
temp=n%m;
n=m;
m=temp;
}
return m;
}
//dfs搜索
void dfs(int cur,int minn,int fz,int fm){
//参数解释,cur代表当前填写的是第cur个分数,minn表示能填写的最小分母,
//fz/fm表示当前剩余的值。
if(n==cur){
//说明我们已经填写到最后一个了,而fz/fm就是剩下的,
//接下来我们要判断是否符合。
if(fm%fz){
//说明fz不为1或者fm=fz,这样都是不符合题意的。
return;
}
a[n] =fm/fz;
if(a[n]>30){
//由于我们填分母是从小到大的,故最后一个的分母是最大的,我们只需要判断它是否越界即可。
return;
}
//打印。
rep(i,1,n-1){
cout<<"1/"<<a[i]<<" ";
}
cout<<"1/"<<a[n]<<endl;
return;
}
//当前填写的是第cur个,我们必须要确定它所能填写的最小分母。这里要设置max以避免打印相同的结果。
minn=max(minn,fm/fz+1);
//确定好了之后,我们开始搜索。
for(int i=minn;;i++){
//我们要与当前还没有填写的分数数与可剩余的做比较,如果fz/fm>=(n-cur+1)/i,即说明以当前分母没办法填完剩余的值。
//相等排除是因为不能有重复分数。
if(fz*i>=(n-cur+1)*fm){
break;
}
//此时就填写。
a[cur]=i;
//fz/fm-1/i。
int temp1,temp2,temp3;
//注意这里不能真的更改fz和fm,如果更改了,会影响接下里for循环里的结果。
temp1=gcd(fz,fm);
temp2=fz*i-fm;
temp3=fm*i;
dfs(cur+1,i+1,temp2/temp1,temp3/temp1);
}
return;
}
void solve(){
memset(a,1,sizeof(a));
dfs(1,2,1,1);
}
int main(){
while(cin>>n){
solve();
}
return 0;
}
hh
1 2 3
蓝桥杯第六届C/C++ B组真题详解_第六届蓝桥杯c加加b组-CSDN博客
蓝桥杯2015第六届C语言B组省赛习题题解——习题F.加法变乘法_2015蓝桥杯省赛c语言b组真题解析-CSDN博客
生命之树
#include <bits/stdc++.h>
using namespace std;
int n;
int a[100005]; // 每个点的点权
long long dp[100005]; // 注意开 long long
vector<int> adj[100005]; // 邻接表存储
void dfs(int u, int fa) {
dp[u] = a[u];
for(int v : adj[u]) {
if(v == fa) continue;
dfs(v, u);
dp[u] += max(dp[v], 0ll);
}
// 状态转移方程
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for(int i = 1, u, v; i < n; i++) {
scanf("%d%d", &u, &v);
adj[u].push_back(v);
adj[v].push_back(u);
}
dfs(1, 0);
printf("%lld", max(*max_element(dp + 1, dp + n + 1), 0ll)); // 输出答案。
return 0;
}
错误:
#include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
ll a, b;
int n;
ll nums[N], dp[N];
vector<ll> tree[N];
bool st[N];
void dfs(int u, int father) {
dp[u] = nums[u];
for (int i = 0; i < tree[u].size(); i ++ )
if (tree[u][i] != father){
dfs(tree[u][i], u);
dp[u] += max(dp[tree[u][i]], ll(0));
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; i ++ ) cin >> nums[i];
while (cin >> a >> b)
tree[a].push_back(b), tree[b].push_back(a);
dfs(1, -1);
ll res = -0x3f3f3f3f;
for (int i = 1; i <= n; i ++ ) res = max(res, dp[i]);
cout << res;
}
第二届国际
题目:蓝桥杯大赛历届真题 - 第二届国际赛真题 - 蓝桥云课 (lanqiao.cn)
2
#include<bits/stdc++.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
using namespace std;
typedef long long ll;
const int MAXN=1e5;//数组所开最大值
const int MOD=1e9+7;//模
const int INF=0x3f3f3f3f;//无穷大
int months[] = {0,31,0,31,30,31,30,31,31,30,31,30,31};
//判断是否是闰年。
int temp[8];//用于存放日期,这样方便去判断是否有符合的数。
int st,st_year,st_month,st_day,ed,ed_year,ed_month,ed_day;
int sum;
bool isLeapYear(int year){
if((year%4==0&&year%100!=0)||(year%400==0)){
return true;
}
else{
return false;
}
}
bool isSpecial(int year,int month,int day){
per(i,3,0){
temp[i] = year%10;
year/=10;
}
per(i,5,4){
temp[i]=month%10;
month/=10;
}
per(i,7,6){
temp[i]=day%10;
day/=10;
}
//接下来开始判断。
int cnt=1;
rep(i,0,6){
if(temp[i]==temp[i+1]){
cnt++;
if(cnt>2){
return true;
}
}
else{
cnt=1;
}
}
return false;
}
void solve(){
sum=0;
st_year = st/10000;
st_month = st/100%100;
st_day = st%100;
ed_year = ed/10000;
ed_month = ed/100%100;
ed_day = ed%100;
//首先进入年去判断。
rep(i,st_year,ed_year){
//接下来开始判断是否是闰年。
if(isLeapYear(i)){
months[2]=29;
}
else{
months[2]=28;
}
if(i==st_year&&i==ed_year){
rep(j,st_month,ed_month){
if(st_month==j&&j==ed_month){
rep(k,st_day,ed_day){
if(isSpecial(i,j,k)){
sum++;
}
}
}
else if(j==st_month){
rep(k,st_day,months[j]){
if(isSpecial(i,j,k)){
sum++;
}
}
}
else if(j==ed_month){
rep(k,1,ed_day){
if(isSpecial(i,j,k)){
sum++;
}
}
}
else{
rep(k,1,months[j]){
if(isSpecial(i,j,k)){
sum++;
}
}
}
}
}
else if(i==st_year){
rep(j,st_month,12){
if(j==st_month){
rep(k,st_day,months[j]){
if(isSpecial(i,j,k)){
sum++;
}
}
}
else{
rep(k,1,months[j]){
if(isSpecial(i,j,k)){
sum++;
}
}
}
}
}
else if(i==ed_year){//*
rep(j,1,ed_month){
if(j==ed_month){
rep(k,1,ed_day){
if(isSpecial(i,j,k)){
sum++;
}
}
}
else{
rep(k,1,months[j]){
if(isSpecial(i,j,k)){
sum++;
}
}
}
}
}
else{
rep(j,1,12){
rep(k,1,months[j]){
if(isSpecial(i,j,k)){
sum++;
}
}
}
}
}
cout<<sum<<endl;
}
int main(){
while(cin>>st>>ed){
solve();
}
return 0;
}
3
/*
*blog:https://blog.csdn.net/hzf0701
*邮箱:unique_powerhouse@qq.com
*注:文章若有任何问题请私信我或评论区留言,谢谢支持。
*/
#include<bits/stdc++.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
using namespace std;
typedef long long ll;
const int maxn=1e5;//数组所开最大值
const int mod=1e9+7;//模
const int inf=0x3f3f3f3f;//无穷大
string s1,s2;
void solve(){
int len1 = s1.size(),len2 = s2.size();
int cnt=0,pos=0;
bool flag = false;
rep(i,0,len1-1){
//查找字符串s1
rep(j,pos,len2-1){
//从之前记录的位置开始查找。
if(s1[i]==s2[j]){
//说明匹配到了第i个。
cnt++;
if(cnt==len1){
cout<<j+1<<endl;
flag = true;
break;
}
pos = j+1;//换下一个位置。
break;
}
}
}
if(!flag){
//说明没有找到。
cout<<-1<<endl;
}
}
int main(){
while(cin>>s1>>s2){
solve();
}
return 0;
}