目录
A、JMU最菜的人是谁?
A-JMU最菜的人是谁?_集美大学"第15届蓝桥杯大赛(软件类)"校内选拔赛 (nowcoder.com)、
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
#define PII pair<int,int>
const int N=1e6+10;
const int INF=1e18;
int n,m;
void solve()
{
cout<<"bei bei shi ji mei da xue zui cai de ren"<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
// cin>>T;
while(T--)solve();
return 0;
}
B、烽火大都督
B-烽火大都督_集美大学"第15届蓝桥杯大赛(软件类)"校内选拔赛 (nowcoder.com)
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
#define PII pair<int,int>
const int N=1e6+10;
const int INF=1e18;
int n,m;
void solve()
{
double a,b,c,d,e;
cin>>a>>b>>c>>d>>e;
cout<<(int)((a+b+c)*(1+d/100)*(e/100))<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
// cin>>T;
while(T--)solve();
return 0;
}
C、20231122
C-20231122_集美大学"第15届蓝桥杯大赛(软件类)"校内选拔赛 (nowcoder.com)
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
#define PII pair<int,int>
const int N=1e6+10;
const int INF=1e18;
int n,m;
void solve()
{
int da=0;
for(int i=2023;i<=20231122;i++)
{
string s="";
int ans=i;
while(ans)
{
s+=(char(ans%10+'0'));
ans/=10;
}
for(int k=0;k+3<s.size();k++)
{
if(s[k]=='2'&&s[k+1]=='2'&&s[k+2]=='1'&&s[k+3]=='1')
{
da++;
break;
}
}
}
cout<<da<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
// cin>>T;
while(T--)solve();
return 0;
}
D、矩阵选数
D-矩阵选数_集美大学"第15届蓝桥杯大赛(软件类)"校内选拔赛 (nowcoder.com)
解法一:dfs 时间O(n!) 大约10分钟
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
#define PII pair<int,int>
const int N=1e6+10;
const int INF=1e18;
int mx;
int arr[100][100],book[100];
void dfs(int sum,int x)
{
if(x==14)
{
mx=max(mx,sum);
return ;
}
for(int i=1;i<=13;i++)
{
if(book[i]==0)
{
book[i]=1;
dfs(sum+arr[x][i],x+1);
book[i]=0;
}
}
}
void solve()
{
for(int i=1;i<=13;i++)
{
for(int j=1;j<=13;j++)
{
cin>>arr[i][j];
}
}
dfs(0,1);
cout<<mx<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
// cin>>T;
while(T--)solve();
return 0;
}
解法二:状压dp 时间:O(
)
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
#define PII pair<int,int>
const int N=1e6+10;
const int INF=1e18;
int mx;
int arr[100][100];
int dp[20][1<<13];
void solve()
{
for(int i=1;i<=13;i++)
for(int j=1;j<=13;j++)
cin>>arr[i][j];
for(int i=1;i<=13;i++)
for(int j=0;j<(1<<13);j++)
for(int k=0;k<13;k++)
if(j>>k&1)
dp[i][j]=max(dp[i][j],dp[i-1][j^(1<<k)]+arr[i][k+1]);
cout<<dp[13][(1<<13)-1]<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
// cin>>T;
while(T--)solve();
return 0;
}
解法三:km算法求二分图最大权匹配O(n*n*n)
根据行和列一一匹配对应的性质,故可划分为二分图匹配类问题,采用KM求最大权匹配即可
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define PII pair<int,int>
#define int long long
const int N=1e3+10;
const int INF=1e18;
int n;
int arr[N][N];//表示S部分和T部分连接的权值。
bool vis_S[N],vis_T[N];
int ex_S[N],ex_T[N],match[N],slack[N];;
bool dfs(int S) {
vis_S[S] = true;
for (int T = 1; T <= n; ++T) {
if (vis_T[T]) {
continue;
}
int gap = ex_S[S] + ex_T[T] - arr[S][T];
if (gap == 0) {
vis_T[T] = true;
if (match[T] == -1 || dfs( match[T] )) {
match[T] = S;
return true;
}
} else {
slack[T] = min(slack[T], gap);
}
}
return false;
}
//KM求最大权匹配。
int KM() {
memset(match, -1, sizeof match);
memset(ex_T, 0, sizeof ex_T);
for (int i = 1; i <= n; ++i) {
ex_S[i] = arr[i][1];
for (int j = 2; j <= n; ++j) {
ex_S[i] = max(ex_S[i], arr[i][j]);
}
}
for (int i = 1; i <= n; ++i) {
memset(slack,0x3f,sizeof(slack));
while (1) {
memset(vis_S, false, sizeof vis_S);
memset(vis_T, false, sizeof vis_T);
if (dfs(i)) break;
int d = INF;
for (int j = 1 ; j <= n; ++j)
if (!vis_T[j]) d = min(d, slack[j]);
for (int j = 1; j <= n; ++j) {
if (vis_S[j]) {
ex_S[j] -= d;
}
if (vis_T[j]) {
ex_T[j] += d;
}
else {
slack[j] -= d;
}
}
}
}
int res = 0;
for (int i = 1; i <= n; ++i)
res += arr[ match[i] ][i];
return res;
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>arr[i][j];
cout<<KM()<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
// cin>>T;
while(T--)solve();
return 0;
}
E、玩《Minecraft》的贝贝
E-玩《Minecraft》的贝贝_集美大学"第15届蓝桥杯大赛(软件类)"校内选拔赛 (nowcoder.com)
采用第三张图和第五张图的策略最优,当n足够大时输出m,否则输出(n+m)/3
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
#define PII pair<int,int>
const int N=1e6+10;
const int INF=1e18;
int n,m;
void solve()
{
cin>>n>>m;
if(m>n)swap(n,m);
if(m>n/2)cout<<(n+m)/3<<endl;
else cout<<m<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
cin>>T;
while(T--)solve();
return 0;
}
F、背单词
F-背单词_集美大学"第15届蓝桥杯大赛(软件类)"校内选拔赛 (nowcoder.com)
容易发现,其每天新背单词所组成的序列会构成1 4 2 1 4 2 1 4 2.......的循环。所以当出现循环后利用公式算答案即可。
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
#define PII pair<int,int>
const int N=1e6+10;
const int INF=1e18;
int n,m;
void solve()
{
cin>>n>>m;
int day=1;
int shang=m;
while(m<n)
{
if(shang%2==0)
{
m+=(shang/2);
shang=(shang/2);
}
else
{
m+=(shang*3+1);
shang=(shang*3+1);
}
day++;
if(shang==2)break;
}
int ans=max(0ll,n-m);
day+=(ans/7)*3;
if(ans%7==0)
{
cout<<day<<endl;
return ;
}
if(ans%7==1)day++;
else if(ans%7>=2&&ans%7<=5)day+=2;
else day+=3;
cout<<day<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
// cin>>T;
while(T--)solve();
return 0;
}
G、堆
G-堆_集美大学"第15届蓝桥杯大赛(软件类)"校内选拔赛 (nowcoder.com)
签到题,维护一个小顶堆和前面总共增加的值即可。
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
#define PII pair<int,int>
const int N=1e6+10;
const int INF=1e18;
void solve()
{
int q;
cin>>q;
priority_queue<int,vector<int>,greater<int> >r;
int sum=0;
while(q--)
{
int op;
cin>>op;
if(op==1)
{
int x;
cin>>x;
r.push(x-sum);
}
else if(op==2)
{
cout<<r.top()+sum<<endl;
r.pop();
}
else
{
int x;
cin>>x;
sum+=x;
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
// cin>>T;
while(T--)solve();
return 0;
}
H、卯酉东海道
H-卯酉东海道_集美大学"第15届蓝桥杯大赛(软件类)"校内选拔赛 (nowcoder.com)
典型最短路模板题,跑一遍dij算法,注意节点更新后,将颜色状态更新到堆中,出队时和当前更新边的颜色做一个判断,如果颜色相同路径不变,颜色不同,那么路径乘以base即可。
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define PII pair<int,int>
#define int long long
const int N=1e6+10;
const int INF=1e18;
int n,m,l,base;
int idx;
int u[N],v[N],w[N],ne[N],first[N],dis[N],book[N][20];
void add(int a,int b,int c)
{
u[idx]=a,v[idx]=b,w[idx]=c,ne[idx]=first[u[idx]],first[u[idx]]=idx,idx++;
}
struct nood{
int u,v,col,w;
};
struct node{
int x,y,col;
friend bool operator<(node a,node b)
{
return a.x>b.x;
}
};
priority_queue<node>r;
vector<nood>ans;
void dij(int x)
{
for(int i=1;i<=n;i++)dis[i]=1e18;
dis[x]=0;
r.push({dis[x],x,l+1});
while(r.size())
{
auto t=r.top();
r.pop();
int k=first[t.y];
int now=t.col;
if(book[u[k]][now])continue;
book[u[k]][now]=1;
while(k+1)
{
if(now==(l+1)&&dis[v[k]]>dis[u[k]]+w[k])
{
dis[v[k]]=dis[u[k]]+w[k];
r.push({dis[v[k]],v[k],ans[k].col});
}
else if(ans[k].col==now&&dis[v[k]]>dis[u[k]]+w[k])
{
dis[v[k]]=dis[u[k]]+w[k];
r.push({dis[v[k]],v[k],ans[k].col});
}
else if(dis[v[k]]>dis[u[k]]+w[k]*base)
{
dis[v[k]]=dis[u[k]]+w[k]*base;
r.push({dis[v[k]],v[k],ans[k].col});
}
k=ne[k];
}
}
}
void solve()
{
cin>>n>>m>>l>>base;
memset(first,-1,sizeof first);
while(m--)
{
int u,v,col,w;
cin>>u>>v>>col>>w;
ans.push_back({u,v,col,w});
add(u,v,w);
}
dij(1);
if(dis[n]==1e18)cout<<-1<<endl;
else cout<<dis[n]<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
// cin>>T;
while(T--)solve();
return 0;
}
I、简单的背包问题
I-简单的背包问题_集美大学"第15届蓝桥杯大赛(软件类)"校内选拔赛 (nowcoder.com)
大容量背包问题,由于价值范围很小,故可以求出n个物品选择恰好价值 i 下所需要的最小容量。再后缀取最小值求出大于每个价值所需要的最小背包容量,对于每个查询进行二分搜索即可。
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define PII pair<int,int>
#define int long long
const int N=1e5+10;
const int INF=1e18;
int dp[3][N];
int sum[N];
int n;
void solve()
{
cin>>n;
memset(dp,0x3f,sizeof dp);
memset(sum,0x3f,sizeof sum);
for(int i=1;i<=n;i++)
{
int w,v;
cin>>w>>v;//表示输入的重量和价值。
if(i==1)
{
dp[i][v]=w;
dp[i][0]=0;
continue;
}
for(int j=0;j<N;j++)
{
if(j>=v)dp[i&1][j]=min(dp[i-1&1][j-v]+w,dp[i-1&1][j]);
else dp[i&1][j]=dp[i-1&1][j];
}
}
for(int i=N-2;i>=0;i--)sum[i]=min(sum[i+1],dp[n&1][i]);
int q;
cin>>q;
while(q--)
{
int x;
cin>>x;
int k=upper_bound(sum,sum+N-1,x)-sum-1;
cout<<k<<endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
// cin>>T;
while(T--)solve();
return 0;
}
J、響符「パワーレゾナンス」
H-卯酉东海道_集美大学"第15届蓝桥杯大赛(软件类)"校内选拔赛 (nowcoder.com)
线段树题,由于题目操作一直向下进行,当值到达0后,操作无效,对于每个数保证能在32次以内得到0。因此可以对于每个区间修改进行暴力操作,维护一个单点操作,对于中间不修改的数据,可以用 并查集/链表/递归标记 的方法。这里给出链表写法,
和参考题解不同的是,其实再链表写法当中,假设题目有操作让值回升,再链表当中依旧可以用logn的时间将该位置插入进去,但是并查集却不可以。因此链表写法和题解的递归标记类似,但时间会略高于递归标记的方法。
对于这个链表可以利用multiset来进行维护
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define PII pair<int,int>
#define int long long
const int N=1e6+10;
const int INF=1e18;
int arr[N],st[N];
int n,m;
int func(int x)
{
return 2*(abs(x*x*x-3*x)/(3*x*x+1));
}
struct nood
{
int l;
int r;
int sum;
};
nood tr[N*4];
void pushup(nood &u, nood &l, nood &r)
{
u.sum=l.sum+r.sum;
}
void pushup(int u)
{
pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}
void build(int u,int l,int r)
{
if(l==r)tr[u]={l,r,arr[r]};
else
{
tr[u]={l,r};
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
}
}
nood ask(int u,int l,int r)
{
if(l>r)return {};
if(tr[u].l>=l&&tr[u].r<=r)return tr[u];
int mid=tr[u].l+tr[u].r>>1;
nood ans;
if(mid>=r)return ask(u<<1,l,r);
else if(mid<l)return ask(u<<1|1,l,r);
else
{
nood zuo=ask(u<<1,l,r);
nood you=ask(u<<1|1,l,r);
pushup(ans,zuo,you);
}
return ans;
}
void add(int u,int x)
{
if(tr[u].l==tr[u].r)
{
int ret=func(tr[u].sum);
if(tr[u].sum==ret)st[x]=1;
tr[u].sum=ret;
}
else
{
int mid=tr[u].l+tr[u].r>>1;
if(mid>=x)add(u<<1,x);
else add(u<<1|1,x);
pushup(u);
}
}
void solve()
{
cin>>n>>m;
multiset<int>book;
for(int i=1;i<=n;i++)
{
cin>>arr[i];
if(arr[i])book.insert(i);
}
build(1,0,N);
while(m--)
{
int op,l,r;
cin>>op>>l>>r;
if(op==1)
{
auto pos_begin=book.lower_bound(l);
auto pos_end=book.upper_bound(r);
if(pos_begin==book.end())continue;
for(auto i=pos_begin;i!=pos_end;)
{
add(1,*i);
if(st[*i]==1)i=book.erase(i);
else i++;
}
}
else
{
cout<<ask(1,l,r).sum<<endl;
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
// cin>>T;
while(T--)solve();
return 0;
}
K、平方数
K-平方数_集美大学"第15届蓝桥杯大赛(软件类)"校内选拔赛 (nowcoder.com)
我认为非常典型且出的好的一个数学题,不难发现,如果两个数相乘的所有质因数的个数都为偶数,那么该乘积一定为完全平方数,因此对于每个数的每个质因数个数的奇偶性求出,若是两个数的每个质因数的奇偶性一一对应相同,那么这两个数的乘积一定是平方数,将每个数的每个奇数位的质因数乘积放入一个set当中,去重输出set集合的个数就是正确答案,
但是这题利用普通的试除筛质因数会T,这里需要用Pollard Rho算法来进行快速质因数分解,但是对于这一题,可以普通方法进行巧妙优化,具体思路如下:
这是题解给出的优化技巧,具体想法是:利用数据再1e9以内的性质,可知每个数大于1000的质因数肯定不超过两个,即一个或者两个,因此后面的质因数完全没必要继续筛下去,只需要判断最后大于1000的质因数乘积是否是平方数,若不是平方数那么将其乘进去。
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define PII pair<int,int>
#define int long long
const int N=1e5+10;
const int INF=1e18;
int n;
int arr[N];
unordered_map<int,int>book;
void solve()
{
cin>>n;
set<int>aas;
for(int i=1;i<=n;i++)
{
cin>>arr[i];
if(book[arr[i]]==1)continue;
book[arr[i]]=1;
int ans=arr[i];
unordered_map<int,int>r;
int res=1;
for(int j=2;j<=ans/j;j++)
{
if(j>1000)break;
int sum=0;
while(ans%j==0)
{
sum++;
ans/=j;
}
if(sum%2==1)res*=j;
}
int q=sqrt(ans);
if(q*q!=ans)res*=ans;
aas.insert(res);
}
cout<<aas.size()<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
// cin>>T;
while(T--)solve();
return 0;
}
L、贝贝的石子游戏
L-贝贝的石子游戏_集美大学"第15届蓝桥杯大赛(软件类)"校内选拔赛 (nowcoder.com)
作为通过人数最少的一题但也是我认为后面三题中最简单的一道题,因为赛时就这题写出来了,而且是秒了QAQ,看很多大佬手动写链表和状压被卡,其实模拟一下不难发现的规律。
先将连续的A和B分别进行合并,最后得到一个类似ABABABAB的一个AB交替的序列,每一个位置的权值当然就是最开始每个连续A或者B的石子重量的最大值。再然后手动模拟,不难发现只需要取除掉左右两边的最大的 个石子即可,具体的贪心证明可见官方题解:
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define PII pair<int,int>
#define int long long
const int N=1e6+10;
const int INF=1e18;
int n;
int arr[N];
int dp[N][3];
void solve()
{
cin>>n;
string s;
cin>>s;
for(int i=1;i<=n;i++)cin>>arr[i];
deque<int>ans;
char shang=s[0];
int res=arr[1];
for(int i=1;i<n;i++)
{
if(s[i]!=shang)
{
ans.push_back(res);
res=0;
}
shang=s[i];
res=max(res,arr[i+1]);
}
ans.push_back(res);
int len=(int)ans.size();
if(len==1||len==2)cout<<0<<endl;
else
{
ans.pop_front();
ans.pop_back();
sort(ans.begin(),ans.end(),greater<int>());
len-=2;
if(len%2==0)
{
int sum=0;
for(int i=0;i<len/2;i++)sum+=ans[i];
cout<<sum<<endl;
}
else
{
int sum=0;
for(int i=0;i<len/2+1;i++)sum+=ans[i];
cout<<sum<<endl;
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
// cin>>T;
while(T--)solve();
return 0;
}