牛客小白月赛6(回顾补题)

官方题解

A 鲲

看起来十分的简单,其实需要分情况讨论。而且题中说在距离大于k时可以选择掉头,当然也可以选择不掉头,同时如果小鲲以到达终点,那么之后其位置都不会改变。或者当距离大于k之后,HtBest开始掉头,但是在掉头途中发现距离又小于k时进行选择这样的。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    double l,k,v1,v2;
    scanf("%lf%lf%lf%lf",&l,&k,&v1,&v2);
    if (v2>=v1)
    {
        double t1=l/v1;
        double t2=l/v2;
        printf("%.2lf\n",t2-t1);
    }
    else
    {
        double dv=v1-v2;
        double dt=k/dv;
        double t1=l/v1;
        double t2=dt*2;
        double dl=l-t2*v1;
        double t;
        if (dl>=k)
        t=min(t2-t1,l/v2-t1);
        else
        t=l/v2-t1;
        printf("%.2lf\n",t);
    }
    return 0;
}

B 鹏

模拟,细心一点就好

#include<bits/stdc++.h>
using namespace std;
vector<long long> p;
int main() {
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++) {
		long long t;
		scanf("%lld",&t);
		p.push_back(t);
	}
	int cnt=0;
	for(int i=0;i<n;i++) {
		int start=i+1;
		while(start<n&&p[start]>=p[start-1])
			start++;
		if(start==n)
			break;
		if(start==(i+1))
			continue;
		while(start<n&&p[start]<=p[start]-1)
			start++;
		cnt++;
		i=start-1;
	}
	printf("%d\n",cnt);
	return 0;
} 

C 桃花

求取树上直径,两遍DFS即可

#include<bits/stdc++.h>
using namespace std;
const int N = 1000050;
typedef struct
{
    int to;
    int pre;
}Line;
Line edge[2 * N];
int f1[N], f2[N],head[N];
int n,tot=1;
int ans = 0;
void Add_edge(int a, int b)
{
    edge[tot].to = b;
    edge[tot].pre = head[a];
    head[a] = tot++;
}
namespace IO {
#define BUF_SIZE 100000
#define OUT_SIZE 100000
#define LL long long
    //fread->read
    bool IOerror = 0;
    inline char nc() {
        static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
        if (p1 == pend) {
            p1 = buf; pend = buf + fread(buf, 1, BUF_SIZE, stdin);
            if (pend == p1) { IOerror = 1; return -1; }
            //{printf("IO error!\n");system("pause");for (;;);exit(0);}
        }
        return *p1++;
    }
    inline bool blank(char ch) { return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; }
    inline void read(int &x) {
        bool sign = 0; char ch = nc(); x = 0;
        for (; blank(ch); ch = nc());
        if (IOerror)return;
        if (ch == '-')sign = 1, ch = nc();
        for (; ch >= '0'&&ch <= '9'; ch = nc())x = x * 10 + ch - '0';
        if (sign)x = -x;
    }
};
void DFS(int now, int pre)
{
    for (int i = head[now]; i; i = edge[i].pre)
    {
        int temp = edge[i].to;
        if (temp== pre)
            continue;
        DFS(temp, now);
        if (f1[now] < f1[temp] + 1)
        {
            f2[now] = f1[now];
            f1[now] = f1[temp] + 1;
        }
        else
            f2[now] = max(f2[now], f1[temp] + 1);
    }
    ans = max(ans, f1[now] + f2[now]);
}
int main()
{
    int a, b;
    IO::read(n);
    for (int i = 1; i < n; i++)
    {
        IO::read(a); IO::read(b);
        Add_edge(a, b);
        Add_edge(b, a);
    }
    DFS(1, 0);
    printf("%d\n", ans + 1);
}

D 字符串丝带

这道题其实很简单,但是比赛的时候没有想到如何解决MLE,其实可以在一开始预处理记录当前位置上的字符前面有几个,之后直接查询就可以,有点可惜。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e6+11;
char s[MAXN];
int num[MAXN];
bool vis[MAXN];
int main() {
	int n,m;
	scanf("%d%d",&n,&m);
	scanf("%s",s);
	for(int i=0;i<n;i++) {
		if(!vis[i]) {
			vis[i]=true;
			int cnt=0;
			for(int j=i;j<n;j++) {
				if(s[j]==s[i]) {
					cnt++;
					num[j]=cnt;
					vis[j]=true;
				}
			}
		}
	}
	for(int i=0;i<m;i++) {
		int t;
		scanf("%d",&t);
		t--;
		printf("%d\n",num[t]);
	}
	return 0;
} 

E 对弈

模拟

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1011;
int n,m;
int graph[MAXN][MAXN];
bool is_win(int x,int y) {
    int cnt=0,sum=graph[x][y],x1=x,y1=y;
    while(x1>=1&&graph[x1][y]==sum)
        x1--,cnt++;
    x1=x+1;
    while(x1<=n&&graph[x1][y]==sum)
        x1++,cnt++;
    if(cnt>=5)
        return true;
    cnt=0;
    while(y1>=1&&graph[x][y1]==sum)
        y1--,cnt++;
    y1=y+1;
    while(y1<=n&&graph[x][y1]==sum)
        y1++,cnt++;
    if(cnt>=5)
        return true;
         
    x1=x,y1=y,cnt=0;
    while(x1>=1&&x1<=n&&y1>=1&&y1<=n&&graph[x1][y1]==sum)
        x1--,y1--,cnt++;
    x1=x+1,y1=y+1;
    while(x1>=1&&x1<=n&&y1>=1&&y1<=n&&graph[x1][y1]==sum)
        x1++,y1++,cnt++;
    if(cnt>=5)
        return true;
     
    x1=x,y1=y,cnt=0;
    while(x1>=1&&x1<=n&&y1>=1&&y1<=n&&graph[x1][y1]==sum)
        x1--,y1++,cnt++;
    x1=x+1,y1=y-1;
    while(x1>=1&&x1<=n&&y1>=1&&y1<=n&&graph[x1][y1]==sum)
        x1++,y1--,cnt++;
    if(cnt>=5)
        return true;
         
    return false;
}
int main() {
    scanf("%d%d",&n,&m);
    bool flag=false;
    for(int i=0;i<m;i++) {
        int x1,y1;
        scanf("%d%d",&x1,&y1);
        graph[x1][y1]=i%2+1;
        if(!flag) {
            if(is_win(x1,y1)) {
                flag=true;
                if(i%2==0)
                    printf("HtBest %d\n",i+1);
                else
                    printf("WHZ %d\n",i+1);
            }
        }
    }
    if(!flag)
        printf("UNK %d\n",m);
    return 0;
}

G 指纹锁

这个题可真是把我难倒了,好好复习了一下set的操作,同时一开始无法删除元素也是很迷啊,万般无奈看了别人的题解发现先往集合中预添加几个较大的数字就可以了。

#include<bits/stdc++.h>
using namespace std;
 
inline bool rd(int &X)
{
    X=0;int w=0;char ch=0;
    while(!isdigit(ch))w|=ch=='-',ch=getchar();
    while( isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    X=w?-X:X; return 1;
}
 
char pd[10];
int m,k,x;
set<int> s;
set<int> :: iterator it;
 
void add(int x)
{
  it=s.lower_bound(x);
  if(abs(*it-x)<=k) return ;
  it--;
  if(abs(*it-x)<=k) return ;
  s.insert(x);
}
void del(int x)
{
  for(it=s.lower_bound(x-k);it!=s.end();)
    if(*it-x>k) {break;}
    else
    {
      int now=*it;
      it++;
      s.erase(now);
    }
}
bool ask(int x)
{
  it=s.lower_bound(x);
  if(abs(*it-x)<=k) return 1;
  it--;
  if(abs(*it-x)<=k) return 1;
  return 0;
}
 
signed main()
{
    rd(m),rd(k);
    s.insert( 100000000);
    s.insert(-100000000);
    while(m--)
    {
      scanf("%s",pd); rd(x);
      if(pd[0]=='a') add(x);
      if(pd[0]=='d') del(x);
      if(pd[0]=='q') ask(x) ? puts("Yes") : puts("No");
    }
}

H 挖沟

作的时候没看出是最小生成树,直接排序然后并查集判定就OK了

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e6+11;
int par[MAXN];
int rank1[MAXN];
struct node{
    int a,b,v;
};
vector<node> p;
bool cmp(node a,node b) {
    return a.v<b.v;
}
void init(int n)
{
    for(int i=1;i<=n;i++) {
        par[i]=i;
        rank1[i]=0;
    }
}
int find(int x)
{
    if(par[x]==x)
        return x;
    else
    {
        return par[x]=find(par[x]);
    }
}
void unite(int x,int y)
{
    x=find(x);
    y=find(y);
    if(x==y)
        return;
    if(rank1[x]<rank1[y])
        par[x]=y;
    else
    {
        par[y]=x;
        if(rank1[x]==rank1[y])
            rank1[x]++;
    }
}
bool same(int x,int y)
{
    return find(x)==find(y);
}
int main() {
    int n,m;
    scanf("%d%d",&n,&m);
    init(n);
    for(int i=0;i<m;i++) {
        node temp;
        scanf("%d%d%d",&temp.a,&temp.b,&temp.v);
        p.push_back(temp);
    }
    sort(p.begin(),p.end(),cmp);
    int cnt=0,ans=0;
    for(int i=0;i<p.size();i++) {
        if(same(p[i].a,p[i].b))
            continue;
        else {
            unite(p[i].a,p[i].b);
            ans+=p[i].v;
            cnt++;
        }
        if(cnt==(n-1))
            break;
    }
    printf("%d\n",ans);
    return 0;
}

I 公交路线

Flody应该拥有姓名,运气好卡过去了(试了很多次)但是还是很大可能TLE

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1011;
const int inf=0x3f3f3f3f;
int graph[MAXN][MAXN];
void init() {
    for(int i=1;i<=1000;i++) {
        for(int j=1;j<=1000;j++) {
            if(i==j)
                graph[i][j]=0;
            else
                graph[i][j]=inf;
        }
    }
}
int main() {
    init();
    int n,m,s,t;
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(int i=0;i<m;i++) {
        int a,b,v;
        scanf("%d%d%d",&a,&b,&v);
        graph[a][b]=graph[b][a]=min(graph[a][b],min(graph[b][a],v));
    }
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                graph[i][j]=min(graph[i][j],graph[i][k]+graph[k][j]);
    if(graph[s][t]==inf)
        printf("-1\n");
    else
        printf("%d\n",graph[s][t]);
    return 0;
}

J 洋灰三角

给出了数列的递推公式,那么我们可以求取出数组的通项公式,使用待定系数法,最终通项公式为:

An=k^{n-1}*(1+\frac{p}{k-1})-(\frac{p}{k-1})  当k等于1时为等差数列,不为1时前半部分使用等比数列的求和公式

Sn=a1*\frac{1-q^{n}}{1-q}  除法部分乘上这个数的逆元(k-1)^{MOD-2}   

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define P 1000000007
int n,k,p,i;
int Pow(int x,int y)
{
    int s=1;
    for(;y;y>>=1,x=(ll)x*x%P)
		if(y&1)
			s=(ll)s*x%P;
    return s;
}
int main()
{
    cin>>n>>k>>p;
    if(k==1)
		cout<<((ll)n*(n-1)/2%P*p+n)%P<<endl;
    else
    {
        i=Pow(k-1,P-2);
        cout<<((1+(ll)p*i)%P*(Pow(k,n)-1)%P*i-(ll)p*n%P*i%P+P)%P<<endl;
    }
    return 0;
}

每次小白月赛的都能有新的收获,自己还是太菜了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值