牛客小白月赛#68
文章目录
- 牛客小白月赛#68
- [A.Tokitsukaze and New Operation](https://ac.nowcoder.com/acm/contest/51958/A)
- [B.Tokitsukaze and Order Food Delivery](https://ac.nowcoder.com/acm/contest/51958/B)
- [C.Tokitsukaze and Average of Substring](https://ac.nowcoder.com/acm/contest/51958/C)
- [D.Tokitsukaze and Development Task](https://ac.nowcoder.com/acm/contest/51958/D)
- [E.Tokitsukaze and Colorful Chessboard](https://ac.nowcoder.com/acm/contest/51958/E)
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;
}