牛客小白月赛#68(A-E)

牛客小白月赛#68

A.Tokitsukaze and New Operation

  • 题意

    • 对于数字串A,B,每一位做乘法计算并把每一位乘积拼贴在一起
  • 题解

    • 签到捏。注意长度不一不能计算,输出-1
    • 字符与数字的转换,手工-'0’或者使用函数to_string等等
  • 代码

#include <iostream>
#include <cstring>

using namespace std;

string solve(string &A,string &B) {
    int lena=A.length(),lenb=B.length();
    string ans="";
    if(lena!=lenb) { ans+="-1"; return ans; }
    
    for(int i=0;i<lena;i++) {
        int sum=(A[i]-'0')*(B[i]-'0');
        ans+=(to_string(sum));
    }
    return ans;
}

int main() {
    int t; cin>>t;
    while(t--) {
        string a,b; cin>>a>>b;
        cout<<solve(a,b)<<'\n';
    }
    return 0;
}

B.Tokitsukaze and Order Food Delivery

  • 题意

    • n家店,第i家店有k道菜及每道菜价格
    • 平台红包满a减b,每家店有对应的满减红包,红包可叠加
    • 问只点一道菜的最小花费
  • 题解

    • 暴力。注意不能花费为负
  • 代码

#include <iostream>

using namespace std;

int main() {
    int T; cin>>T;
    while(T--) {
        int ans=0x3f3f3f3f;
        int n,a,b; scanf("%d%d%d",&n,&a,&b);
        while(n--) {
            int k,x,y; scanf("%d%d%d",&k,&x,&y);
            for(int i=0;i<k;i++) {
                int price; scanf("%d",&price);
                int t=price;
                if(t>=x) price-=y;
                if(t>=a) price-=b;
                if(price<0) price=0;
                ans=min(ans,price);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

C.Tokitsukaze and Average of Substring

  • 题意

    • si==sj (i<j)表示相同字符对。C(l,r)表示s[l~r]中相同字符对数量。
    • 问F(l,r)=C(l,r)/(r-l+1)的最大值
  • 题解

    • 预处理(前缀和思想)。暴力枚举l,r来确定每一个区间的复杂度n*n可以接受,但在确定区间后再计算F会炸
    • 于是思考能不能预处理出C的值。容易发现C有一定的递推性,所以对于区间C(l,r)的值其实就是C(l,r-1)的值加上s[r]_sum(l,r-1)字符s[r]在区间[l,r-1]出现的次数
    • 所以可以先用前缀和预处理出,26个字符在字符串区间中出现的次数。随后即可n*n遍历区间后,借用sum一边递推C,一边O(1)查询出F值
  • 代码

#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    int t; cin>>t;
    while(t--) {
        int n; string s="?",str="";
        cin>>n>>str;
        s+=str;
        
        vector sum(n+1,vector<int>(26));
        for(int i=1;i<=n;i++) 
            for(int j=0;j<26;j++)
               sum[i][j]=sum[i-1][j]+(s[i]-'a'==j);
        
        vector C(n+1,vector<int>(n+1));
        double ans=0;
        for(int i=1;i<=n;i++)
            for(int j=i;j<=n;j++) {
                int x=sum[j-1][s[j]-'a']-sum[i-1][s[j]-'a'];
                C[i][j]=C[i][j-1]+x;
                ans=max(ans,1.0*C[i][j]/(j-i+1));
            }
        printf("%.6lf\n",ans);
    }
    return 0;
}

D.Tokitsukaze and Development Task

  • 题意

    • 四种资源从(10,10,10,10)通过8种操作达到(a,b,c,d)的最小操作数
  • 题解

    • 初状态到最终状态求最小操作数可以用bfs,可以发现每种资源都是独立的,所以四种次数相加即可
    • bfs跑前要建图,10-300的点都进行8种操作。注意边数不确定,所以用vector建图
    • 记录10到每个点的最短次数,最后相加输出即可
  • 代码

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <cstring>

using namespace std;
const int N=310;
int dis[N],vis[N];
vector<int> g[N];

void add(int u,int v) {
    if(max(u,v)>300) return ;
    if(min(u,v)<10) return ;
    g[u].push_back(v);
}

int main() {
  //build
    for(int i=10;i<=300;i++) {
        add(i,i+1); add(i,i-1);
        add(i,i+10); add(i,i-10);
        add(i,i+100); add(i,i-100);
        add(i,300); 
        add(i,10);
    }
    
  //bfs
    memset(dis,0x3f,sizeof dis);
    queue<int> q;
    dis[10]=0,vis[10]=1,q.push(10);
    while(q.size()) {
        int now=q.front();
        q.pop();
        for(auto to:g[now]) {
            if(!vis[to]) {
                dis[to]=min(dis[to],dis[now]+1);
                q.push(to);
                vis[to]=1;
            }
        }
    }
    
    int T; cin>>T;
    while(T--) {
        int a,b,c,d; cin>>a>>b>>c>>d;
        cout<<dis[a]+dis[b]+dis[c]+dis[d]<<'\n';
    }
    return 0;
}

E.Tokitsukaze and Colorful Chessboard

  • 题意

    • n*n的棋盘,放黑白两种子,颜色相同的不能有上下左右的相邻
    • 问给定a黑子,b颗白字,最小的棋盘长度n为多少
  • 题解

    • 贪心,两种子尽量把格子占满可以使得n最小。
    • 画图得,n为奇数时:最多能放n2/2+1个、n2/2个;n为偶数时:两个都放n^2/2
    • a+b最大数据范围为2*109,故n不超过105。且随着n的改变导致单调的a,b变化,所以可以直接二分n
  • 代码

#include <iostream>

using namespace std;
#define int long long

signed main() {
    int t; cin>>t;
    while(t--) {
        int a,b; cin>>a>>b;
        if(a<b) swap(a,b);
        
        int l=1,r=1e5;
        while(l<=r) {
            int mid=(l+r)/2;
            int sum=mid*mid/2;
            if(mid&1) sum+=1;
            
            if(a>sum || a+b>mid*mid) l=mid+1;//判断条件大的数值a和最大的限制格子数比
            else r=mid-1;
        }
        cout<<l<<'\n';
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值