ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

第十二届蓝桥杯B组真题题解

2022-02-09 02:31:52  阅读:258  来源: 互联网

标签:组真题 return int 题解 long 蓝桥 括号 const include


第十二届蓝桥杯B组真题题解

时间显示

简单的模拟题,换算好时间就行

#include<cstdio>

int main()
{
    long long n;
    scanf("%lld", &n);
    n /= 1000;
    n %= 60 * 60 * 24;
    printf("%02d:%02d:%02d\n", n / 3600, n / 60 % 60, n % 60);
    return 0;
}

砝码称重

可以用dp做也可以直接母函数来做。都是比较模板的题hdu1709原题。写文章-CSDN博客生成函数相关知识可以参考我之前写的这篇来学习,重点在理解c1和c2在模拟多项式的作用。问题比这个简单一点。稍微改改就行,不直接贴ac代码了

#include <bits/stdc++.h>
using namespace std;
const int maxn=100005;
int n,c1[maxn],c2[maxn],num[105];
int elem[105];
int main() {
    while (~scanf("%d",&n)){
        for (int i=1;i<=n;i++)scanf("%d",&elem[i]),num[i]=1;
        int sum=0;
    	for (int i=1;i<=n;i++)sum+=elem[i]*num[i];//num全为1,此处为了模板好修改,好理解。
        memset(c1,0,sizeof(c1));
        memset(c2,0,sizeof(c2));
    	c1[0]=c1[elem[1]]=1;
    	for (int i=2;i<=n;i++){
    		for (int j=0;j<=sum;j++)
    			for (int k=0;k+j<=sum&&k<=elem[i];k+=elem[i])
    			{
    				c2[abs(k-j)]+=c1[j];//天平问题唯一的区别就是可以组合出k和j的绝对值,加上即可。
    				c2[j+k]+=c1[j];
    			}
    		for (int j=0;j<=sum;j++){
    			c1[j]=c2[j];
    			c2[j]=0;
    		}
    	}
    	vector<int>ans;
    	for (int i=0;i<=sum;i++)
    		if (!c1[i])ans.push_back(i);
    	printf("%lu\n",ans.size());
    	for (int i=0;i<ans.size();i++)
    		printf("%d%c",ans[i],i==ans.size()-1?'\n':' ');
    }
    return 0;
}


杨辉三角

结合了二分和数学。首先杨辉三角对称。所有右边不考虑。对于左边斜着看,由于每个斜行都是单调的,并且16行也是递增的。所以可以结合二分和组合数来找到位置。注意从最多16层。因为C(32,16)大于1e9.只需要二分找到位置,再用公式计算它的具体位置即可

#include <iostream>
#include <cstring>
#include <algorithm>
#define int long long
using namespace std;
int n;
int c(int a,int b){
    int res=1;
    for(int i=a,j=1;j<=b;i--,j++)
        res=res*i/j;
    return res;
}
bool check(int k){
    int l=2*k,r=max(n,l);
    while(l<r){
        int mid=(l+r) >>1;
        if(c(mid,k)>=n)r=mid;
        else l=mid+1;
    }
    if(c(r,k)!=n)return false;
    else{
        cout<<(r+1)*r/2+k+1;
        return 1;
    }
}
signed main(){
    cin>>n;
    for(int k=16;;k--){
        if(check(k)){
            return 0;
        }
    }
}
 

双向排序

2016 天津oi省选的题的弱化版。可以直接用线段树合并和分解做,对每个位置建立权值线段树,维护下排序的过程即可,不过这题弱化了一些地方,所以不需要这么麻烦的方法。观察性质,分情况讨论,用栈维护也可以通过这题。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int inf=0x3f3f3f3f,mod=1e9+7;
const int N=1e5+10;
int n,m,top,tot;
int rt[N],stk[N*40],op[N];
struct node{
    int l,r,x;
}q[N*40];
set<int>s;
inline int newnode(){return top?stk[top--]:++tot;}
inline void del(int u){q[stk[++top]=u]={0,0,0};}
void upd(int &u,int l,int r,int p)
{
    q[u=++tot].x=1;
    if(l==r) return;
    int m=(l+r)>>1;
    if(p<=m) upd(q[u].l,l,m,p);
    else upd(q[u].r,m+1,r,p);
}
void print(int u,int l,int r,int f)
{
    if(!u) return;
    if(l==r) cout<<l<<" ";
    int m=(l+r)>>1;
    if(f)
    {
        print(q[u].l,l,m,f);
        print(q[u].r,m+1,r,f);
    }
    else
    {
        print(q[u].r,m+1,r,f);
        print(q[u].l,l,m,f);
    }
}
void split(int x,int &y,int k,int f)
{
    if(!x) return;
    y=newnode();
    if(f)
    {
        int v=q[q[x].l].x;
        if(k<=v)
        {
            if(k<v) split(q[x].l,q[y].l,k,f);
            swap(q[x].r,q[y].r);
        }
        else split(q[x].r,q[y].r,k-v,f);
    }
    else
    {
        int v=q[q[x].r].x;
        if(k<=v)
        {
            if(k<v) split(q[x].r,q[y].r,k,f);
            swap(q[x].l,q[y].l);
        }
        else split(q[x].l,q[y].l,k-v,f);
    }
    q[y].x=q[x].x-k;
    q[x].x=k;
}
int merge(int x,int y)
{
    if(!x||!y) return x+y;
    q[x].x+=q[y].x;
    q[x].l=merge(q[x].l,q[y].l);
    q[x].r=merge(q[x].r,q[y].r);
    del(y);
    return x;
}
auto spl(int x)
{
    auto it=s.lower_bound(x);
    if(*it==x) return it;
    --it;split(rt[*it],rt[x],x-*it,op[x]=op[*it]);
    return s.insert(x).first;
}
int main(void)
{
    sync;
    cin>>n>>m;
    s.insert(n+1);
    for(int i=1;i<=n;++i)
    {
        upd(rt[i],1,n,i);
        s.insert(i);
    }
    while(m--)
    {
        int o,l,r=n;
        cin>>o>>l;
        if(o==0) r=l,l=1;
        auto L=spl(l),R=spl(r+1);
        for(auto it=++L;it!=R;++it)
            rt[l]=merge(rt[l],rt[*it]);
        op[l]=o;s.erase(L,R);
    }
    for(int x:s)
    {
        if(x==n+1) break;
        print(rt[x],1,n,op[x]);
    }
    return 0;
}
 

括号序列

一个比较特殊的dp题,容易发现,所有间隔都可以插入括号,但是插入()形式的括号没有意义,所以括号格式一定是)(的,那么问题就变成了插入左括号的方案数乘插入右括号的方案数即可算出答案。所以我们只需要考虑左括号的插入方案数即可,定义dp[I] [j]的状态为前i个括号,左括号比右括号多j个的方案数,那么分情况讨论,状态转移方程很容易列出

如果当前是左括号,f[i] [j]=f[i-1] [j-1];

如果当前是右括号,f[i] [j]=f[i-1] [j+1]+....f[i-1] [0]

对于第二种情况,可以用完全背包的技巧,减少一维,从小到大枚举,至于右括号,翻转序列,然后在改变括号,跑一边就行。注意由于要求添加最少,所以答案是第一个存在方案的,f[n] [j]。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 5010;
char s[N];
ll f[N][N];
int n;
int get()
{
    memset(f, 0, sizeof f);

    f[0][0] = 1;
    for(int i = 1; i <= n; i ++ )
        if(s[i] == '(')
        {
            for(int j = 1; j <= n; j ++ )
            f[i][j] = f[i - 1][j - 1];
        }
        else
        {
            f[i][0] = (f[i - 1][0] + f[i - 1][1]) % mod;
            for (int j = 1; j <= n; j ++ )
                f[i][j] = (f[i - 1][j + 1] + f[i][j - 1]) % mod;
        }
    for(int i = 0; i <= n; i ++ )
        if(f[n][i])
            return f[n][i];
}
int main()
{
    scanf("%s", s + 1);
    n = strlen(s + 1);
    ll l = get();
    reverse(s + 1, s + n + 1);
    for(int i = 1; i <= n; i ++ )
        if(s[i] == '(') s[i] = ')';
        else s[i] = '(';
    ll r = get();
    cout << l * r % mod;
}

标签:组真题,return,int,题解,long,蓝桥,括号,const,include
来源: https://www.cnblogs.com/tscjj/p/15873499.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有