【2019 10th C++】 蓝桥杯决赛

\(\checkmark\)

题意

\(2019<X<Y\),使得\(2019\times 2019 , X\times X , Y\times Y\)构成等差数列,且\(X+Y\)的值尽量小

题解

枚举\(X\)的值,只要\(X\)的值确定了,得到\(Y\),通过开根后平方判断是不是一个整数

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)

int main(){
    int X,Y;
    int a=2019*2019;
    rep(i,2020,100000){
        int del=i*i-a;
        double y2=i*i+del;
        int y=sqrt(y2);
        if(y*y==y2){
            X=i,Y=y;
            break;
        }
    }
    cout<<X+Y<<endl;
}

答案

7020

\(\checkmark\)

题意

求解两两不同的素数构成\(2019\)的方案数

题解

\(01\)背包求数字部分和问题

  • \(dp[0\sim cnt][0]\)的边界问题

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define ll long long 
const int N=2019+10;
ll dp[N][N];
int primes[N],cnt;
bool st[N];
void get()
{
    rep(i,2,2019)
    {
        if(!st[i]) primes[++cnt]=i;
        for(int j=1;primes[j]<=2019/i;j++)
        {
            st[primes[j]*i]=1;
            if(i%primes[j]==0) break;
        }
    }
}

int main()
{
    get();
    rep(i,0,cnt) dp[i][0]=1;

    rep(i,1,cnt) rep(j,1,2019)
    {
        dp[i][j]=dp[i-1][j];
        if(j>=primes[i]) dp[i][j] += dp[i-1][j-primes[i]];
    }
        
    cout<<dp[cnt][2019]<<endl;
}

答案

55965365465060

\(\checkmark\)

题意

求约数个数为\(100\)的最小整数

题解

从小到大暴力枚举即可

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)

int main()
{
    int ans;
    for(int i=2;;i++)
    {
        int d=0;
        for(int j=1;j<=i;j++)
        {
            if(i%j==0) d++;
        }
        if(d==100)
        {
            ans=i;
            break;
        }
    }
    cout<<ans<<endl;
}

答案

45360

题意

将一个\(7\times 7\)的方格沿着边剪开后,右半部分水平翻转后再旋转拼接在左边那块的不规则处,要求拼成的还是一个矩形,求有多少种裁剪方法

题解

Code


\(\checkmark\)

题意

有一个\(7\times 7\)的方格。方格左上角顶点坐标为\((0,0)\),右下角坐标为\((7,7)\)
求满足下列条件的路径条数:

1、起点和终点都是\((0,0)\)

2、路径不自交

3、路径长度不大于\(12\)

4、对于每一个顶点,有上下左右四个方向可以走,但是不能越界。

题解

  • \(dfs\)所有可能的行走方向,在每一个\(dfs\)路径中,标记已经走过的节点,不能重复行走

  • 当满足走到\((0,0)\)\(step\;!=\;0,step\leq 12\),累计答案

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)

const int N=15;
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
bool st[N][N];
int ans;
void dfs(int x,int y,int step)
{
    if(step>12) return;
    if(!x && !y && step<=12 && step)
    {
        ++ans;
        return;
    }
    rep(i,0,3)
    {
        int tx=x+dx[i],ty=y+dy[i];
        if(tx >= 0 && tx<7 && ty >= 0 && ty<7)
        {
            if(st[tx][ty]) continue;
            st[tx][ty]=1;
            dfs(tx,ty,step+1);
            st[tx][ty]=0;
        }
    }
}
int main()
{
    dfs(0,0,0);
    cout<<ans<<endl;
}

答案

208

六. 最优包含\(\checkmark\)

题意

给定两个字符串\(A\)\(B\),保证\(A\)的长度不小于\(B\)的长度,问至少修改\(A\)的多少个字符,可以令\(B\)成为\(A\)的子序列。

题解

子序列不是连续的,所以只要下标的大小关系不变并且包含\(B\)的每一个字母即可

  • \(dp[i][j]\)表示\(A\)的前\(i\)个包含\(B\)的前\(j\)个的操作次数

  • 状态转移:\(dp[i][j]=min(dp[i-1][j],dp[i-1][j-1]+(A[i]!=B[j]))\)

注意开始边界的定义\(dp[0][0]=0\)

数据范围

\(1\leq |A|,|B|\leq 1000\)

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)
const int N=1010;
char a[N],b[N];
int dp[N][N];
int n,m;
int main(){
    scanf("%s%s",a+1,b+1);
    n=strlen(a+1);m=strlen(b+1);
    memset(dp,0x3f,sizeof dp);
    rep(i,0,n) dp[i][0]=0; 
    rep(i,1,n) rep(j,1,m){
        dp[i][j]=dp[i-1][j];
        dp[i][j]=min(dp[i][j],dp[i-1][j-1]+(a[i]!=b[j]));
    }
    printf("%d\n",dp[n][m]);
}

七. 排列数字

题意

对于一个数列中的某个数,如果这个数比两侧的数都大或比两侧的数都小,我们称这个数为这个数列的一个转折点。
如果一个数列有\(t\)个转折点,我们称这个数列为\(t+1\)调数列。
给定两个正整数\(n,k\)。求在\(1\sim n\)的全排列中,有多少个数列是\(k\)调数列。

数据范围

\(1\leq k\leq n\leq 500\)

题解

  • \(dfs\)求数字的全排列,判断当前是否存在\(k-1\)个转折点,如果是的话累计个数

  • 可行性剪枝,如果转折点超过或者加上剩下的所有点数都不够就剪枝

  • 每次递归开始的时候累加转折点,所以判断的时候要\(+1\)因为在\(u=n+1\)的时候存储了\(n\)个值的全排列

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)
const int N=1010;
int n,k;
int path[N];
int ans;
bool st[N];
int a[N];
bool check(int x)
{
    if(path[x-1]>path[x]&&path[x]<path[x+1]) return 1;
    if(path[x-1]<path[x]&&path[x]>path[x+1]) return 1;
    return 0;
}
void dfs(int u,int sum)
{
    if(u>=4) // 边界问题
    {
        if(check(u-2)) sum++;
    }
    if(u == n+1)
    {
        if(sum== k-1) ans++;
        return;
    }

    if(sum > k-1 || sum+n-u+1 < k-1) return;
    rep(i,1,n)
    {
        if(st[i]) continue;
        st[i]=1;
        path[u]=i;
        dfs(u+1,sum);
        st[i]=0;
    }
}
int main()
{
    scanf("%d%d",&n,&k);
    dfs(1,0);
    printf("%d\n",ans);
}

八.解谜游戏

题意

题解

Code


九. 第八大奇迹\(\checkmark\)

题意

给定一个长度为\(n\)的序列,初始所有的值都为\(0\),给定\(m\)个操作,操作有两种

  • \((C,x,y)\):将第\(x\)位置上的值修改为\(y\)

  • \((Q,x,y)\):查询问下标为\(x\sim y\)区间中的第\(8\)大数字

数据范围

\(1\leq n,m\leq 10^{5}\)

题解

每次求的只有第\(k\)大的数字,所以线段树的每个节点利用\(vector\)维护当前区间内部的前\(8\)大的数字

  • \(vector\)每次\(push\_back\)都需要动态增加空间,导致\(TLE\),所以在初始化过程中通过\(resize\)将其变为数组

  • 每次修改操作后通过引用的方式改变更新节点前八大的数字

数组不能作为函数返回值,所以需要用\(vector\)作为数组进行使用

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)
const int N=1e5+10;

int n,m;
struct node {
    int l,r;
    vector<int>p;
    #define l(u) u*2
    #define r(u) u*2+1
}tr[N*4];
void pushup(vector<int>&u,const vector<int>&left,const vector<int>&right){
    int i=0,j=0,cnt=0;
    rep(t,1,8){
        if(left[i]>=right[j]) u[cnt++]=left[i],i++;
        else u[cnt++]=right[j],j++;
    }
}   

void build(int u,int l,int r){
    tr[u].l=l;
    tr[u].r=r;
    tr[u].p.resize(8);
    if(l==r){
        tr[u].p[0]=0;
        return;
    }
    int mid=l+r>>1;

    build(l(u),l,mid);
    build(r(u),mid+1,r);
}

void modify(int u,int id,int x){
    if(tr[u].l==tr[u].r){
        tr[u].p[0]=x;
        return;
    }

    int mid=tr[u].l+tr[u].r>>1;
    if(id<=mid) modify(l(u),id,x);
    else modify(r(u),id,x);

    pushup(tr[u].p,tr[l(u)].p,tr[r(u)].p);
}
vector<int> query(int u,int l,int r){
    if(tr[u].l >= l && tr[u].r <= r) return tr[u].p;
    int mid=tr[u].l+tr[u].r>>1;

    if(r<=mid) return query(l(u),l,r);
    if(l>mid) return query(r(u),l,r);

    vector<int>ans(8,0);
    pushup(ans,query(l(u),l,r),query(r(u),l,r));
    return ans;
}

int main(){
    scanf("%d%d",&n,&m);
    char op[2];int x,y;
    build(1,1,n);
    while(m--){
        scanf("%s%d%d",op,&x,&y);
        if(op[0]=='C') modify(1,x,y);
        else printf("%d\n",query(1,x,y)[7]);
    }
    return 0;
}   

十.燃烧权杖

题意

数据范围

题解

Code


posted @ 2020-10-28 21:16  Hyx'  阅读(18)  评论(0编辑  收藏  举报