牛客练习赛35 BCE题解

本文深入解析算法竞赛中常见问题的解决策略,包括单词计数动态规划、函数操作的图搜索算法以及比赛歌曲选择的后缀数组应用。通过具体代码示例,详细介绍了如何高效求解复杂问题,为参赛者提供宝贵的实战经验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

B.背单词

设d[ i ][ j ][ k ] 为在第从1到第 i 个字母,后缀连续长度为 j (j=0为元音,1位辅音)的种类数,很显然转移方程为:

d[ i ][ 0 ][ j+1 ]=d[ i-1 ][ 0 ][ j ]*5,辅音则乘以21,d[ i ][ 0 ][ 1 ]=5*( d[ i-1 ][ 1 ][ k ](k=1,2,,,B)),还有一个读者自己可以推,很简单。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=5005,mod=1e9+7;
ll d[maxn][2][55];
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int n,a,b;
		cin>>n>>a>>b;
		ll ans=0;
		for(int i=1;i<=n;i++)
		{
			ll res1=d[i-1][0][a],res2=d[i-1][1][b];
			for(int j=1;j<a;j++)
			if(i-j>=0)
			d[i][0][j+1]=d[i-1][0][j]*5%mod,res1+=d[i-1][0][j],ans+=d[i][0][j+1];
			for(int j=1;j<b;j++)
			if(i-j>=0)
			d[i][1][j+1]=d[i-1][1][j]*21%mod,res2+=d[i-1][1][j],ans+=d[i][1][j+1];
			if(i==1)
			res1=res2=1;	
			d[i][0][1]=res2*5%mod;
			d[i][1][1]=res1*21%mod;
			ans+=d[i][0][1];
			ans+=d[i][1][1];
		}
		cout<<ans%mod<<endl;
	}
}

C.函数的魔法

思路:因为最多只有233种情况,所以我只要从A开始跑bfs即可,很简单。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int vis[250],d[250];
int dij(int s,int t)
{
	queue<int>q;
	q.push(s);
	memset(vis,0,sizeof(vis));
	d[s]=0;
	while(!q.empty())
	{
		int x=q.front();q.pop();
		int y=(x*x*x+x*x)%233;
		if(!vis[y])
		{
			q.push(y);
			d[y]=d[x]+1;
			vis[y]=1;
			if(y==t)return d[y];
		}
		y=(x*x*x-x*x)%233;
		if(!vis[y])
		{
			q.push(y);
			d[y]=d[x]+1;
			vis[y]=1;
			if(y==t)return d[y];			
		}
	}
	return -1;
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		if(a==b)
		{
			puts("0");
			continue;
		}
		if(b>=233)
		{
			puts("-1");
			continue;
		}
		printf("%d\n",dij(a%233,b));
	}
}

E.μ‘s挑选比赛歌曲

思路:比赛时题意读漏了,赛后发现加特判就过了(被自己蠢哭了),首先我们要快速求出所有歌曲的最长公共子串长度,看是否超过K,怎么求呢?还记得后缀数组的height数组吗,没错,我们把所有歌曲拼接成一个字符串,然后求后缀数组,然后枚举height数组把所有长度超过k的不同后缀串用G数组标记,最后状态压缩枚举所有状态,用G数组判断该状态是否合法即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn=8e5+1000;
int G[25];
int id[maxn];
struct S_array
{
    int sa[maxn],t[maxn],t2[maxn],c[maxn],n;
    char  s[maxn];
    void build_sa(int m)
    {
        int i,*x=t,*y=t2;
        for(i=0;i<m;i++)c[i]=0;
        for(i=0;i<n;i++)c[x[i]=s[i]]++;
        for(i=1;i<m;i++)c[i]+=c[i-1];
        for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
        for(int k=1;k<=n;k<<=1){
            int p=0;
            for(i=n-k;i<n;i++)y[p++]=i;
            for(i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
            for(i=0;i<m;i++)c[i]=0;
            for(i=0;i<n;i++)c[x[y[i]]]++;
            for(i=0;i<m;i++)c[i]+=c[i-1];
            for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
            swap(x,y);
            p=1;x[sa[0]]=0;
            for(i=1;i<n;i++)
            x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
            if(p>=n)break;
            m=p;
        }
    }
    int rank[maxn],height[maxn];
    void getHeight()
    {
        int i,j,k=0;
        for(i=0;i<n;i++)rank[sa[i]]=i;
        for(i=0;i<n;i++){
            if(k)k--;
            int j=sa[rank[i]-1];
            while(s[i+k]==s[j+k])k++;
            height[rank[i]]=k;
        }
    }
    void ss(int k)
    {
        int vis[21],flag=0;
        memset(vis,0,sizeof(vis));
        for(int i=1;i<n-1;i++)
        if(height[i]>=k)
        {
            vis[id[sa[i]]]=1;
            vis[id[sa[i-1]]]=1;
            flag=1;
        }
        else if(flag)
        {
            flag=0;
            for(int j=1;j<=20;j++)
            for(int p=1;p<j;p++)
			if(vis[j]&&vis[p])
			G[j]|=(1<<p-1),G[p]|=(1<<j-1);
			memset(vis,0,sizeof(vis));
        }
    }
}sa;
int main()
{
    int n,k,m,x,cnt=0,mn=25,res=0;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&m);
        if(m<k)res++;
        for(int j=1;j<=m;j++)
        scanf("%d",&x),id[cnt]=i,sa.s[cnt++]=x+25;
        mn--;
        sa.s[cnt++]=mn;
    }
    sa.n=cnt;
    sa.build_sa(150);
    sa.getHeight();
    sa.ss(k);
    int all=(1<<n)-1;
    int ans=1;
    for(int i=1;i<=all;i++)
    {
        int p=0,s=0;
        for(int j=0;(1<<j)<=i;j++)
        if(i&(1<<j))
        s|=G[j+1],p++;
        if((s^i)==all)
        ans=max(ans,p);
    }
    ans-=res;
    cout<<ans;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙橘子猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值