牛客小白月赛22总结
前言:
本来觉得能进前一百的,但是,害…
B题如果做出来了,就肯定能进前一百了。感觉B应该不难,但是就是不知道怎么做,最终以四题告终(A、E、F、J)
看当时比赛的情况,感觉这四道题+B题都是非常简单的题,毕竟都AC都超过了一百。继续加油,题解出来认真补题!!!
先总结下自己做出来的四道题:
A:操作序列
题意:
无线长度的数列,初始状态都为0,有三种操作:
增加操作:给下标为 t 的数加 c 。特别注意,如果在下标 [t-30,t+30][t−30,t+30] 内有不为零的数,增加操作无效。(可以这样理解,要想该操作能进行,则必须这个范围的数都为0)
削减操作:让数列中下标最小的不为零数变为零。(如果全都为0,则输出skipped)
查询操作:查询数列中下标为 t 的数字是多少。
题解:
A真的搞我的心态,第一遍看题的时候没有注意到时间,觉得非常难,就直接没管,等到看了一会B的时候,再来看A,才发现时间限制居然是5s,起初想到的是map,毕竟map能自动排序嘛;写出来到写成功花了将近一个小时。。。。。结果一交TLE ,这心态瞬间崩了,然后继续看B,B仍然不会做,于是想着用结构体数组来模拟一下A,结果一交,居然过了。。。。
AC代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<sstream>
#include<string>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#define lowbit(x) x&(-x)
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const double pi=3.14159;
const int maxn=1e6+5;
map<int,int>mp;
char s[10];
int n,pos,num;
struct node{
int p,x;
};
node a[maxn+10];
int t;
bool cmp(node x,node y){
return x.p>y.p;
}
int main(){
scanf("%d",&n);
getchar();
t=0;
while(n--){
pos=0,num=0;
gets(s);
int len=strlen(s);
int flag=0;
int po;
for(int i=0;i<len;i++){
if(s[i]==' '){
po=i;
flag=1;
break;
}
}
if(s[0]=='-'){
if(t==0){
printf("skipped\n");
}
else{
printf("%d\n",a[--t].x);
}
}
else if(flag==0){
int bit=1;
for(int i=len-1;i>=0;i--){
pos+=(s[i]-'0')*bit;
bit*=10;
}
int Flag=0;
for(int i=0;i<t;i++){
if(a[i].p==pos){
printf("%d\n",a[i].x);
Flag=1;
break;
}
}
if(Flag==0){
printf("0\n");
}
}
else{
int bit=1;
for(int i=po-1;i>=0;i--){
pos+=(s[i]-'0')*bit;
bit*=10;
}
bit=1;
for(int i=len-1;i>po;i--){
num+=(s[i]-'0')*bit;
bit*=10;
}
int Flag=0;
for(int i=0;i<t;i++){
if(a[i].p>=(pos-30)&&a[i].p<=(pos+30)){
Flag=1;
break;
}
}
if(Flag==0){
a[t].p=pos;
a[t].x=num;
t++;
sort(a,a+t,cmp);
}
}
}
return 0;
}
E:方块涂色
题意:
n*m的矩阵,初始状态都是没有涂色的,现在给定可以对r行,c列涂色;问最终剩余多少方块没有涂色
题解:
开始还觉得有点难,其实一想发现很简单
被涂上的方块数 num = rm+cn-(rc)
于是最终结果为:nm-num
AC代码如下:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<sstream>
#include<string>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#define lowbit(x) x&(-x)
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=4e5+10;
ll n,m,r,c;
int main(){
while(~scanf("%lld%lld%lld%lld",&n,&m,&r,&c)){
ll num=n*m;
ll num1=r*m+c*n-(r*c);
cout<<num-num1<<endl;
}
return 0;
}
F:累乘数字
题意:
给定n,d;求n乘以100次d的结果
题解:
非常裸的大整数,只是我仍然不喜欢用C++写大数,还是用的Java
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
public class Main {
public static void main(String args[]) {
Scanner scan=new Scanner(System.in);
while(scan.hasNext()) {
BigInteger n=scan.nextBigInteger();
int d=scan.nextInt();
for(int i=1;i<=d;i++) {
n=n.multiply(BigInteger.valueOf(100));
}
System.out.println(n);
}
}
}
J:计算A+B
题意:
每组给定一个字符串,然后需要判断是不是a+b的形式
(例如:+10、0+、01+001这些都不是a+b形式)
ps:可能出题人觉得前导0会没有那么水,在比赛中取消了前导0,但是我的代码仍然考虑了前导0,当时通知的时候已经敲完了QAQ。。。
如果不是a+b形式,输出skipped
如果是的话,输出结果
题解:
也是大整数、高精度相关问题。
只是会比上一题稍微复杂一点点,仍然用的Java
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
public class Main {
public static void main(String args[]) {
Scanner scan=new Scanner(System.in);
int n=scan.nextInt();
for(int k=1;k<=n;k++) {
String s=scan.next();
char[] arr=s.toCharArray();
int len=s.length();
int pos=0;
for(int i=0;i<len;i++) {
if(arr[i]=='+') {
pos=i;
break;
}
}
if(pos==0||pos==len-1) {
System.out.println("skipped");
continue;
}
if(arr[0]=='0'&&pos!=1) {
System.out.println("skipped");
continue;
}
if(arr[pos+1]=='0'&&(pos+1)!=len-1) {
System.out.println("skipped");
continue;
}
BigInteger a=BigInteger.ZERO;
BigInteger b=BigInteger.ZERO;
BigInteger bit=BigInteger.ONE;
for(int i=pos-1;i>=0;i--) {
a=a.add(BigInteger.valueOf(arr[i]-'0').multiply(bit));
bit=bit.multiply(BigInteger.valueOf(10));
}
bit=BigInteger.ONE;
for(int i=len-1;i>pos;i--) {
b=b.add(BigInteger.valueOf(arr[i]-'0').multiply(bit));
bit=bit.multiply(BigInteger.valueOf(10));
}
System.out.println(a.add(b));
}
}
}
补题部分…
B:树上子链
题意:
给定一棵树 T ,树 T 上每个点都有一个权值。
定义一颗树的子链的大小为:这个子链上所有结点的权值和 。
请在树 T 中找出一条最大的子链并输出。
题解:
好吧,我人傻了;居然是求树的直径,害,一道模板题
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<sstream>
#include<string>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#define lowbit(x) x&(-x)
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e5+10;
struct Edge{
int to,nxt;
}edge[maxn*2];
int tot;
int head[maxn];
int vis[maxn];
ll dp[maxn];
int val[maxn];
ll ans;
void init(){
tot=0;
ans=-inf;
memset(head,0,sizeof(head));
memset(vis,0,sizeof(vis));
memset(edge,0,sizeof(edge));
memset(val,0,sizeof(val));
memset(dp,0,sizeof(dp));
}
void add(int u,int v){
tot++;
edge[tot].to=v;
edge[tot].nxt=head[u];
head[u]=tot;
}
void dfs(int u,int pre){
dp[u]=val[u];
ans=max(ans,dp[u]);
for(int i=head[u];i!=0;i=edge[i].nxt){
int v=edge[i].to;
if(v==pre){
continue;
}
dfs(v,u);
ans=max(ans,dp[u]+dp[v]);
dp[u]=max(dp[u],dp[v]+val[u]);
}
}
int main(){
init();
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&val[i]);
}
int u,v;
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs(1,-1);
printf("%lld\n",ans);
return 0;
}
C:交换游戏
题意:
一列上有12个孔,这12个孔中有些孔被遮挡住了。
假定我们用 ‘-’ 来表示没被遮挡住的孔,用 ‘o’ 来表示被遮挡住的孔。
如果相邻的三个孔有两个孔被遮挡,并且被遮挡的两个孔相邻,就是 ‘-oo’ 和 ‘oo-’。
对于这样的三个孔,我们可以将中间的孔的遮挡物移开,代价是将一端的遮挡物移到另一端没有被遮挡的孔上面。
对于一列给定的孔,你的任务是制定操作的顺序,使得最后剩余的被遮挡的孔的个数最少,并输出最后剩余的被遮挡的孔的个数。
题解:
居然直接暴力搜,害,马虎了
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<sstream>
#include<string>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#define lowbit(x) x&(-x)
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e5+10;
int n;
string s;
int ans;
void dfs(){
for(int i=2;i<12;i++){
if(s[i-2]=='-'&&s[i-1]=='o'&&s[i]=='o'){
s[i-2]='o';
s[i-1]='-';
s[i]='-';
dfs();
s[i-2]='-';
s[i-1]='o';
s[i]='o';
}
if(s[i-2]=='o'&&s[i-1]=='o'&&s[i]=='-'){
s[i-2]='-';
s[i-1]='-';
s[i]='o';
dfs();
s[i-2]='o';
s[i-1]='o';
s[i]='-';
}
}
int num=0;
for(int i=0;i<12;i++){
if(s[i]=='o'){
num++;
}
}
ans=min(ans,num);
}
int main(){
cin>>n;
while(n--){
ans=inf;
cin>>s;
dfs();
cout<<ans<<endl;
}
return 0;
}
G:仓库选址
题意:
m*n的矩阵,在其中选择一点,使得其他点这个点的距离之和最小
题解:
这题其实很水啊,比赛的时候看都没看,可惜了
直接暴力枚举即可。。。。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<sstream>
#include<string>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#define lowbit(x) x&(-x)
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e5+10;
int t,n,m;
int mp[110][110];
int solve(int x,int y){
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(i==x&&j==y)
continue;
ans+=mp[i][j]*(abs(x-i)+abs(y-j));
}
}
return ans;
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&m,&n);
memset(mp,0,sizeof(mp));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&mp[i][j]);
}
}
int ans=inf;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int num=solve(i,j);
ans=min(ans,num);
}
}
cout<<ans<<endl;
}
return 0;
}