蓝桥杯校园练习

算法训练 字符串变换

问题描述
  相信经过这个学期的编程训练,大家对于字符串的操作已经掌握的相当熟练了。今天,徐老师想测试一下大家对于字符串操作的掌握情况。徐老师自己定义了1,2,3,4,55个参数分别指代不同的5种字符串操作,你需要根据传入的参数,按照徐老师的规定,对输入字符串进行格式转化。
  徐老师指定的操作如下:
  1 表示全部转化为大写字母输出,如abC 变成 ABC
  2 表示全部转换为小写字母输出,如abC变成abc
  3 表示将字符串整个逆序输出,如 abc 变成 cba
  4 表示将字符串中对应的大写字母转换为小写字母,而将其中的小写字母转化为大写字母输出,如 abC变成ABc
  5表示将全部转换为小写字母,并将其中所有的连续子串转换为对应的缩写形式输出,比如abcD 转换为a-d,其次,-至少代表1个字母,既如果是ab,则不需要转换为缩写形式。
输入格式
  一共一行,分别是指代对应操作的数字和字符串,两者以空格分隔,字符串全部由英文字母组成
输出格式
  输出根据上述规则转换后对应的字符串
样例输入
5 ABcdEE
样例输出
a-ee
数据规模和约定
  输入字符串长度最长为200

模拟题,直接贴代码,注意s跟i的含义。

#include <bits/stdc++.h>
using namespace std;
int main(){
    int tp,top[1111];
    char st[1111];
    scanf("%d %s",&tp,st);
    if(tp==1){
        for(int i=0;i<strlen(st);i++){
            if('a'<=st[i]&&st[i]<='z') putchar(st[i]-32);
            else putchar(st[i]);
        }
        puts("");
    }
    if(tp==2){
        for(int i=0;i<strlen(st);i++){
            if('A'<=st[i]&&st[i]<='Z') putchar(st[i]+32);
            else putchar(st[i]);
        }
        puts("");
    }
    if(tp==3){
        for(int i=strlen(st)-1;i>=0;i--) putchar(st[i]);
        puts("");
    }
    if(tp==4){
        for(int i=0;i<strlen(st);i++){
            if('A'<=st[i]&&st[i]<='Z') putchar(st[i]+32);
            if('a'<=st[i]&&st[i]<='z') putchar(st[i]-32);
        }
        puts("");
    }
    if(tp==5){
        for(int i=0;i<strlen(st);i++)if('A'<=st[i]&&st[i]<='Z') st[i]+=32;
        int s=0;
        while(s<strlen(st)){
            int i;
            for(i=s+1;i<strlen(st);i++)
                if(st[i]!=st[i-1]+1) break;
            i--;
            if(i==s||i==s+1){
                putchar(st[s]);
                s++;
                continue;
            }
            else{
                putchar(st[s]);
                putchar('-');
                putchar(st[i]);
                s=i+1;
            }
        }
    }
    return 0; 
} 

算法提高 快速幂

求 A^B%P
二分快速幂

#include <cstdio>
#include <iostream>
using namespace std;
long long a,b,p;
long long bigpow(long long x, long long y){
    long long ret = 1;
    long long tmp = x;
    while (y > 0){
        if (y & 1) ret = (ret%p)*(tmp%p)%p;
        y >>= 1;
        tmp = (tmp%p) * (tmp%p) % p;
    }
    return ret;
}
int main(){
    cin >>a>>b>>p;
    cout<<bigpow(a,b)<<endl;
    return 0;
}

算法提高 线段和点

问题描述
有n个点和m个区间,点和区间的端点全部是整数,对于点a和区间[b,c],若a>=b且a<=c,称点a满足区间[b,c]。
求最小的点的子集,使得所有区间都被满足。

贪心??????
每次选能覆盖最多区间的点。

#include <bits/stdc++.h>
using namespace std;
bool dian[50009];
bool v[11111];
struct node{
    int l,r;
}sec[11111];
bool cmp(node t1,node t2){
    return ((t1.l<t2.l)||(t1.l==t2.l)&&(t1.r<t2.r));
}
int main(){
    int n,m,x;
    scanf("%d%d",&n,&m);
    memset(dian,0,sizeof(dian));
    memset(v,0,sizeof(v)); 
    for(int i=1;i<=n;i++){
        scanf("%d",&x);
        dian[x]=1;
    }
    for(int i=1;i<=m;i++){
        scanf("%d%d",&sec[i].l,&sec[i].r);
    }
    sort(sec+1,sec+1+m,cmp);
    int ans=0,E;
    for(int i=1;i<=m;i++){
        int mx=-INT_MAX;
        if(!v[i]){
            for(int j=sec[i].l;j<=sec[i].r;j++){
                if(dian[j]){
                    int tot=0;
                    for(int k=i+1;k<=m;k++){
                        if(sec[k].l<=j&&j<=sec[k].r){
                            tot++;
                        }
                        else break;
                    }
                    if(tot>mx){
                        mx=tot;
                        E=j;
                    }
                }
            }
            ans++;
            for(int k=i+1;k<=m;k++){
                if(sec[k].l<=E&&E<=sec[k].r){
                    v[k]=1;
                }
                else break;
            }
        }
    }
    printf("%d\n",ans);
    return 0;
} 

算法提高 理财计划

#include <iostream>
#include <cstdio>
using namespace std;
int main(){
    int k, n;
    double p;
    cin>>k>>n>>p;
    double ans = 0;
    for(int i=1;i<=n;i++) {
        ans=ans+k;
        ans=ans*(1+p);
    }
    printf("%.2f", ans-n*k);
    return 0;
}

算法提高 超级玛丽

F[n]=F[n-1]+F[n-2],F[n]=0,(n为陷阱)
# include <stdio.h>
# include <string.h>
int n, m;
int dp[50],flag[50];
int g[50];
int main(){
    int i, j, k, num, flage;
    scanf("%d%d", &n, &m);
    for(int i=1;i<=m;i++){
        int x;
        scanf("%d",&x);
        flag[x]++;
    }
    if(flag[1]==0) dp[1]=1;
    if(flag[2]==0) dp[2]=1;
    for(int i=3;i<=n;i++){
        if(flag[i]==0) dp[i]=dp[i-1]+dp[i-2];
        else dp[i]=0; 
    } 
    printf("%d\n",dp[n]);
    return 0;
}

算法训练 连续正整数的和

#include <cstdio>
using namespace std;
int main(){
    int s;
    scanf("%d",&s);
    for(int i=1;i<=s;i++){
        for(int j=i+1;j<=s;j++){
            int sum = (i+j)*(j-i+1)/2;
            if(sum==s) printf("%d %d\n",i,j);
            if(sum>s) break;
        }
    }
    return 0;
} 

算法提高 盾神与砝码称重

n个砝码,看看能不能称出m的重量。
搜索题,裸搜复杂度O(3^n),亲测50分

#include <bits/stdc++.h>
#define base 1000000
using namespace std;
int w[25];
int info[11];
int n,m;
bool f0[2000001],f1[2000001];

int dfs(int noww,int id){
    if(!noww) return 1;
    if(id==n+1&&noww!=0){
        return 0;
    }
    return dfs(noww-w[id],id+1)||dfs(noww,id+1)||dfs(noww+w[id],id+1);
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&w[i]);

    sort(w+1,w+1+n);

    for(int i=1;i<=m;i++){
        int x;
        scanf("%d",&x);
        puts(dfs(x,1)?"YES":"NO");
    }

    return 0;
}

优化,将砝码从小到大排序,求一个前缀和,从大的砝码开始取,若剩下的砝码质量不及当前质量的绝对值,return 0。

#include <bits/stdc++.h>
using namespace std;
int w[25];
int info[11];
int n,m;
int sum[25];
inline int dfs(int noww,int id){
    if(!noww) return 1;
    if(id==0&&noww!=0){
        return 0;
    }

    if(abs(noww)>sum[id]) return 0;
    for (;id>=1;id--){
        if (dfs(noww-w[id], id-1)||dfs(noww+w[id], id-1)){
            return 1;
        }
    }
    return 0;
}
inline bool cmp(int x,int y){return x<y;}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&w[i]);
    sort(w+1,w+1+n,cmp);
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]+w[i];
    for(int i=1;i<=m;i++){
        int x;
        scanf("%d",&x);
        puts(dfs(x,n)?"YES":"NO");
    }
    return 0;
}

优化2:每次做到一个质量然后hash,此种做法80分,这里就不贴了。

算法训练 开心的金明

dp,经典老题。
01背包

#include <bits/stdc++.h>
using namespace std;
int N, m, v[30005], p[33];
int f[30005];
int main(){
    int ans;
    scanf("%d%d", &N, &m);
    for(int i=1; i<=m; i++){
        scanf("%d%d", &v[i], &p[i]);
    }

    for(int i=1;i<=m;i++)
        for(int j=N;j>=0;j--)
            if(j>=v[i]) f[j] = max(f[j],f[j-v[i]]+v[i]*p[i]);


    ans=-INT_MAX;
    for(int i=N; i>=0; i--){
        ans = max(f[i], ans);
    }
    printf("%d\n", ans);
    return 0;
}

历届试题 剪格子

问题描述
如下图所示,3 x 3 的格子中填写了一些整数。


+--*--+--+
|10* 1|52|
+--****--+
|20|30* 1|
*******--+
| 1| 2| 3|
+--+--+--+

我们沿着图中的星号线剪开,得到两个部分,每个部分的数字和都是60。

本题的要求就是请你编程判定:对给定的m x n 的格子中的整数,是否可以分割为两个部分,使得这两个区域的数字和相等。

如果存在多种解答,请输出包含左上角格子的那个区域包含的格子的最小数目。

如果无法分割,则输出 0。

dfs裸搜
判断是否合法的时候麻烦点,要再写个dfs统计联通块,checkb中,f1为已取格子数,f2为未取格子数,随便找一个未取的,看看能不能遍历完。f1+f2==n*m则符合要求。

#include <bits/stdc++.h>
using namespace std;
int g[11][11];
int v[13][13];
int v2[13][13]; 
int range[13][13];
const int dx[]={0,1,-1,0,0};
const int dy[]={0,0,0,-1,1};
int n,m,s=0,mn=INT_MAX;
int find(int x, int y, int id){
    if(v2[x][y]) return 0;
    int tot=0;
    if(range[x][y]==0) return 0;
    if(v[x][y]!=id) return 0;
    if(v[x][y]==id) tot++;
    v2[x][y]=1;
    for(int i=1;i<=4;i++){
        tot += find(x+dx[i],y+dy[i],id);
    }
    return tot;
}

bool checkb(int x,int y){
    memset(v2,0,sizeof(v2));
    int f1=find(x,y,1);
    int f2;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            if(v[i][j]==1) continue;
            memset(v2,0,sizeof(v2));
            f2=find(i,j,0);
            return f1+f2==m*n;
        }
}

bool check(int i,int j){
    if(!range[i][j]) return 0;
    v[i][j]=1;
    bool pan=checkb(i,j);
    v[i][j]=0;
    return pan;
}

int dfs(int i,int j,int dep,int s){
    if(s<g[i][j]) return 0;
    if(v[i][j]) return 0;
    if(check(i,j)==0) return 0;
    if(s==g[i][j]){
        if(dep<mn) mn=dep;
        return 0;
    }
    v[i][j]=1;
    for(int cnt=1;cnt<=4;cnt++){
        dfs(i+dx[cnt],j+dy[cnt],dep+1,s-g[i][j]);
    }
    v[i][j]=0;
}

int main(){
    scanf("%d%d",&m,&n);
    memset(v,0,sizeof(v));
    memset(range,0,sizeof(range));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            scanf("%d",&g[i][j]);
            s+=g[i][j];
            range[i][j]=1;
        }
    if(s%2==1){
        puts("0");
        return 0;
    }
    s/=2;
    dfs(1,1,0,s);
    printf("%d\n",mn+1);
    return 0;
}

历届试题 九宫重排

经典的八数码问题。宽搜裸的话不知道能拿多少分。
多种方法求解八数码问题links
这边说一个在网上看到的结论。
对于八数码问题,有解的话,步数一定是在32步以内的。如果bfs层数超过32,直接-1即可
还有,百度如何正确有效地使用hash。
贴上一份代码。

#include <bits/stdc++.h>
using namespace std;
const int dx[] = {-1, 1, 0, 0};
const int dy[] = {0, 0, -1, 1};
int htable[10007],f,r;
int next[444444];
int Q[444444][9];
int zeros[444444];
int vis[444444];
int purpose[9];
int pre[444444];
int hash(int pos){
    int num = 0;
    for(int i = 0; i < 9; i++){
        num = num*10+Q[pos][i];
        num%=10007;
    }
    return num;
}
bool insert(int pos){
    int num=hash(pos);
    for(int n=htable[num];n!=-1;n=next[n]){
        if(memcmp(Q[n],Q[pos],sizeof(Q[pos]))==0)
            return false;     
    }
    next[pos]=htable[num];
    htable[num]=pos;
    return true;
}
int bfs(){
    pre[0]=-1;
    while(f<r){
        int *now = Q[f++];
        if(memcmp(now, purpose, sizeof(purpose)) == 0)
            return f-1;
        int zx = zeros[f-1]/3;
        int zy = zeros[f-1]%3;
        for(int i = 0; i < 4; i++){
            int nowx = zx+dx[i];
            int nowy = zy+dy[i];
            if(nowx < 0 || nowx >=3 || nowy < 0 || nowy >= 3)
                continue;
            int (*next)[3] = (int (*)[3])Q[r++];
            memcpy((int *)next, now, sizeof(int)*9);
            next[zx][zy] = next[nowx][nowy];
            next[nowx][nowy] = 0;
            zeros[r-1] = nowx*3+nowy;
            pre[r-1] = f-1;
            if(!insert(r-1))
                r--;
        }
    }
    return -1;
}
int main(){
    memset(htable, -1, sizeof(htable));
    f=0,r=0;
    for(int i = 0; i < 9; i++){
        char ch;
        ch=getchar();
        if(ch == '.') {
            Q[0][i] = 0;
            zeros[0] = i;
        }
        else
            Q[0][i] = ch-'0';
    }
    getchar();
    r++;
    for(int i = 0; i < 9; i++){
        char ch;
        ch=getchar();
        if(ch=='.') purpose[i]=0;
        else  purpose[i]=ch-'0';
    }
    int tot=0;
    for(int p=bfs();p!=-1;p=pre[p])
        tot++;
    printf("%d\n",tot-1);
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值