集美大学“第15届蓝桥杯大赛(软件类)“校内选拔赛补题

目录

A、JMU最菜的人是谁?

B、烽火大都督

C、20231122

D、矩阵选数

解法一:dfs   时间O(n!)   大约10分钟 

解法二:状压dp  时间:O()

解法三:km算法求二分图最大权匹配O(n*n*n)

E、玩《Minecraft》的贝贝

F、背单词

G、堆

H、卯酉东海道

I、简单的背包问题

J、響符「パワーレゾナンス」

K、平方数

L、贝贝的石子游戏


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(n*n*2^{n})

#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,看很多大佬手动写链表和状压被卡,其实模拟一下不难发现[n/2]的规律。

先将连续的A和B分别进行合并,最后得到一个类似ABABABAB的一个AB交替的序列,每一个位置的权值当然就是最开始每个连续A或者B的石子重量的最大值。再然后手动模拟,不难发现只需要取除掉左右两边的最大的 ceil(n/2) 个石子即可,具体的贪心证明可见官方题解:

代码如下:

#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;
}

  • 40
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值