牛客小白月赛47
传送门
A-牛牛的装球游戏
大致题意:在圆柱体中放半径相同的球,求剩余体积
解题思路:只要圆柱体的高度h对球的直径2*r取模就可以求得球的个数n,圆柱体体积减去n个球的体积即为剩余体积
注意细节:π的取值已给出,输出结果保留三位小数
coding
#include<iostream>
#include<iomanip>
using namespace std;
#define PI 3.141592653589
int main()
{
int T;
cin>>T;
while(T--){
int r,h;
cin>>r>>h;
//计算球和圆柱体的体积
double s1=4/3.0*PI*r*r*r,s2=PI*r*r*h;
//计算最多可以放入的球的个数
int n=h/(r*2);
cout<<fixed<<setprecision(3);//保留三位小数
cout<<s2-n*s1<<endl;
}
return 0;
}
B-牛牛的数字集合
大致题意:给定n个数,划分为m个集合,如何划分使得价值和最小,集合价值:集合中数的乘积的m次方,结果对1e9+7取模
解题思路:不难发现,划分越多,价值和就会越大,最佳选择就是不划分,直接就一个集合。
思路证明:写不出来,不知道怎么表达意思
注意细节:数的范围和个数都在1e6以内,所有数相乘可能会爆,每次相乘时都要取模
coding
#include<iostream>
using namespace std;
typedef long long LL;
const int MOD=1e9+7;
int main()
{
int n;
cin>>n;
LL res=1;
for(int i=0;i<n;i++){
int x;
cin>>x;
res=res*x%MOD;
}
cout<<res;
return 0;
}
C-小猫排队
大致题意:小猫啾啾排在n只猫咪后,她每隔一分钟可以施展魔法(与前面距离最近且可爱值大于她的猫咪交换位置),先施展魔法然后排最前面的离开,计算需要几分钟才能离开
解题思路:使用双端队列deque模拟施法及移动过程,由于只会向前移动,所以直接将换到后面的猫咪弹出队列即可
注意细节:当前面没有可以换的猫咪时应该按顺序排,但我们已经将他们弹出队列,所以在弹他们时要记录个数,比赛期间就是因为这个卡住了-__-;注意将离开的队头弹出
coding
#include<iostream>
#include<deque>
using namespace std;
int main()
{
int n;
cin>>n;
deque<int> q;//队列
while(n--){
int x;
cin>>x;
q.push_back(x);
}
int x;//啾啾的可爱值
cin>>x;
int res=0;
while(true){
int b=0;//记录前面有几个小于等于啾啾的
//由于只会向前交换,所以不需要考虑换到后面的猫咪,所以直接弹出队列
while(q.size()&&q.back()<=x){
q.pop_back();
b++;
}
//如果没有能换的,那就按顺序走
if(q.empty()){
res+=(b+1);
break;
}
q.pop_back();//和大于啾啾的猫咪交换位置
res++;
if(q.empty()) break;
q.pop_front();//队头离开
}
cout<<res;
return 0;
}
D-造桥
大致题意:n个字符串首尾连接(当前字符串尾部和下一字符串首部相同则可连接),得到一个尽可能长的字符串
解题思路:线性dp,每个字符串有取和不取两种状态;设字符串开头、结尾和长度为x,y,m;状态转移方程为f[i][y]=max(f[i-1][y],f[i-1][x]+m);分别对应取和不取两种状态,其中状态之间互不影响,所以第一维状态可省略
注意细节:多组数据,所以需要将数组清零;size()和length()返回无符号整数
coding
#include<iostream>
#include<cstring>
using namespace std;
int f[26];
int main()
{
int T;
cin>>T;
while(T--){
memset(f,0,sizeof f);
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
string s;
cin>>s;
int m=s.size();
f[s[m-1]-'a']=max(f[s[m-1]-'a'],f[s[0]-'a']+m);
}
int res=0;
for(int i=0;i<26;i++)
res=max(res,f[i]);
cout<<res<<endl;
}
return 0;
}
E-牛牛的方格图
大致题意:给定一个n*m的矩阵,每个格子有一种颜色;两个相同颜色的点矩形之间视为被覆盖,求有多少个未被覆盖的点
思路:存储每种颜色横纵坐标的最大最小值(左上角和右下角),用差分矩阵(作用:给连续区间同时加上一个数)的方式上标记,标记为0的就是没有被覆盖的点
注意细节:输入超过1e5,最好使用scanf输入
coding
#include<iostream>
#include<cstdio>
using namespace std;
const int N=1010,M=1000010;
int a[M][4];//每个颜色的横纵坐标的最大最小值
int sum[N][N];//前缀和
int main()
{
for(int i=1;i<=1e6;i++)
a[i][1]=a[i][3]=1e4;//横纵坐标最小值赋初值
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
int x;//颜色
scanf("%d",&x);
a[x][0]=max(a[x][0],i);
a[x][1]=min(a[x][1],i);
a[x][2]=max(a[x][2],j);
a[x][3]=min(a[x][3],j);
}
for(int i=1;i<=1e6;i++){//枚举每种颜色
if(a[i][0]==0) continue;//没有这种颜色
if(a[i][0]==a[i][1]&&a[i][2]==a[i][3]) continue;//最大值=最小值,说明只有一种颜色,无法覆盖
//差分矩阵
sum[a[i][0]+1][a[i][2]+1]++;//左上角
sum[a[i][0]+1][a[i][3]]--;//右上角
sum[a[i][1]][a[i][2]+1]--;//左下角
sum[a[i][1]][a[i][3]]++;//右下角
}
//求前缀和
int res=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
if(sum[i][j]==0) res++;//没有被覆盖
}
cout<<res;
return 0;
}

浙公网安备 33010602011771号