牛客练习赛78 A--C

链接

A CCA的词典

题目描述
给定一个有 n 个单词的词典 。
有 q 次询问,每次询问给定一个单词,询问有多少个单词可以通过交换相邻字母(也可以不交换)变成给定的单词 。
输入描述:
第一行一个整数 n 。
接下来 n 行,每行一个单词 。
第 n+2 行一个整数 q 。
接下来 q 行每行一个单词,表示询问 。
输出描述:
共 q 行,每行一个整数,表示有多少个所求单词 。
示例1
输入
复制
4
aa
bb
ab
ba
2
aa
ba
输出
复制
1
2
备注:
n,q <= 10^4,单词长度 <= 2,单词中的字母全为小写。

属于签到题

#include <bits/stdc++.h>
#define inf 0x7fffffff
#define ll long long
//#define int long long
//#define double long double
#define eps 1e-8
//#define mod 1e9+7
using namespace std;
const int p=1e9+7;
const int M=1e7+5;
const int N=1e4+5;//?????????? 4e8
int n,m;
string s;
map < string , int > mp;
void solve()
{
    cin>>n;
    while(n--)
    {
        cin>>s;
        mp[s]++;
        if(s.size()==2)
        {
            if(s[0]==s[1])  continue;
            char ch=s[0];
            s[0]=s[1];
            s[1]=ch;
            mp[s]++;
        }
    }
    cin>>m;
    while(m--)
    {
        cin>>s;
        cout<<mp[s]<<endl;
    }
}
signed main()
{
//  ios::sync_with_stdio(false);
//  cin.tie(0);cout.tie(0);
    solve();
    return 0;
}

B CCA的搬运

题目描述
在一个竖直的洞里有 n 个有重量的球,需要进行 m 次操作,每次操作需要将其中一个球拿出来然后放在最上面 。
取出一个小球放在最上面需要消耗的体力为它上面的小球的重量之和 。
现在给定每次操作需要取的小球的编号,要求出一种初始的放球方案使得消耗的总体力最少 。
输入描述:
第一行两个正整数 n 和 m,意义如题所示 。
第二行 n 个正整数,分别表示 n 个球的重量 。
第三行 m 个正整数,分别表示 m 次操作取出小球的编号 。

输出描述:
一个整数表示消耗的总体力的最小值 。
示例1
输入
复制
3 3
1 2 3
3 2 1
输出
复制
8
备注:
n,m <= 2000,1 <= 每个小球的重量 <= 100 。

找了半天规律,结果发现暴力就可以解决,吐了。
属于坑爹题。

#include <bits/stdc++.h>
#define inf 0x7fffffff
#define ll long long
#define int long long
//#define double long double
#define eps 1e-8
//#define mod 1e9+7
using namespace std;
const int p=1e9+7;
const int M=1e7+5;
const int N=1e4+5;//?????????? 4e8
int n,m,t;
int b[N],pos[N];
int ans;
map < int , int > mp,mp2; 
int a[N],v[N];
void solve()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)  scanf("%lld",&a[i]);
	for(int i=1;i<=m;i++)  scanf("%lld",&pos[i]);
	for(int i=1;i<=m;i++)
	{
		b[++t]=pos[i];
		while(pos[i]==pos[i+1]&&i+1<=m)  i++;
//		cout<<i<<endl;
	}
//	for(int i=1;i<=t;i++)  cout<<b[i]<<" ";
//	cout<<endl;
	for(int i=1;i<=t;i++)
	{
		mp2.clear();
		for(int j=i-1;j>mp[b[i]]&&j;j--)
		{
			if(mp2[b[j]])  continue;
			ans+=a[b[j]];
			mp2[b[j]]=1;
		}
//		cout<<i<<" "<<ans<<endl;
		mp[b[i]]=i;
	}
	cout<<ans<<endl;
}
signed main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0);cout.tie(0);
	solve();
	return 0;
}

C CCA的子树

题目描述
给定一棵 n 个点的带点权的有根树,根节点为 1 。
要选出两个节点,满足任意一个不是另一个的祖先节点,最大化以两个节点为根的子树的点权和 。
如果选不出两棵合法的子树,则输出“Error”。
输入描述:
第一行一个正整数 n 。
第二行 n 个整数,分别表示 n 个点的点权 。
接下来 n - 1 行,每行两个正整数 u,v 表示 u 和 v 之间有一条连边 。
输出描述:
一个整数,表示最大的点权和
示例1
输入
复制
5
10 -5 5 6 7
1 2
1 3
2 4
2 5
输出
复制
13
备注:
n <= 2×10^5,点权的绝对值 <= 10^9

居然可以一发过,没想到,真是没想到,还担心会超时。

简单来说,就是一道LCA题,要找两个子树根节点,使他们的和最大,且两子树不能再同一颗子树内

但是想的超时的情况是这样的,如图(最后找图的循环)

在这里插入图片描述

于是我优化了一下,改变根节点,不过后来证明数据比较水

(不过我还是把优化的代码粘上)

#include <bits/stdc++.h>
#define inf 0x7fffffff
#define ll long long
#define int long long
//#define double long double
#define eps 1e-8
//#define mod 1e9+7
using namespace std;
const int p=1e9+7;
const int M=1e7+5;
const int N=1e6+5;//?????????? 4e8
int n,t;
struct node
{
	int ver,next;
}e[N];
int a[N],b[N],fa[N];
int f[N][64];
int root;
struct aa
{
	int val,pos;
}sz[N],d[N];
int tot,head[N],flag;
int dep[N];
void add(int x,int y)
{
	e[++tot].ver=y;
	e[tot].next=head[x];
	head[x]=tot;
}
void addedge(int x,int y)
{
	add(x,y);add(y,x);
}
bool cmp(aa x,aa y)
{
	return x.val>y.val;
}
void dfs1(int x,int pre)
{
	sz[x].val=a[x];
	sz[x].pos=x;
	for(int i=head[x];i;i=e[i].next)
	{
		int y=e[i].ver;
		if(y==pre)  continue;
		dfs1(y,x);
		sz[x].val+=sz[y].val;
	}
}
void check(int x,int pre)
{
	int fl=0;
	for(int i=head[x];i;i=e[i].next)
	{
		int y=e[i].ver;
		if(y==pre)  continue;
		fl++;
		check(y,x);
	}
	if(fl>=2)  flag=1,root=x;
}
void bfs()
{
	queue < int > q;
	q.push(1);
	dep[1]=1;
	while(q.size())
	{
		int x=q.front();q.pop();
		for(int i=head[x];i;i=e[i].next)
		{
			int y=e[i].ver;
			if(dep[y])  continue;
			dep[y]=dep[x]+1;
			f[y][0]=x;
			for(int j=1;j<=t;j++)  f[y][j]=f[f[y][j-1]][j-1];
			q.push(y);
		}
	}
}
int lca(int x,int y)
{
	if(dep[x]>dep[y])  swap(x,y);
	for(int i=t;i>=0;i--)  if(dep[f[y][i]]>=dep[x])  y=f[y][i];
	if(x==y)  return x;
	for(int i=t;i>=0;i--)  if(f[x][i]!=f[y][i])  x=f[x][i],y=f[y][i];
	return f[x][0];
}
void solve()
{
	cin>>n;
	t=(int)log(n)/log(2)+1;
	for(int i=1;i<=n;i++)  scanf("%lld",&a[i]);
	for(int i=1;i<n;i++)
	{
		int x,y;
		scanf("%lld%lld",&x,&y);
		addedge(x,y);
	}
	check(1,1);
//	cout<<root<<endl;
	if(!flag)
	{
		puts("Error");
		return;
	}
	bfs();
	dfs1(root,root);
    
	for(int i=1;i<=n;i++)  d[i]=sz[i];
	sort(d+1,d+n+1,cmp);
	for(int i=1;i<=n;i++)
	{
		if(d[i].pos==1)  continue;
		for(int j=i+1;j<=n;j++)
		{
			if(d[j].pos==1)  continue;
			int LCA=lca(d[i].pos,d[j].pos);
			if(LCA!=d[i].pos&&LCA!=d[j].pos)
			{
				cout<<d[i].val+d[j].val<<endl;
//				cout<<d[i].pos<<" "<<d[j].pos<<" "<<LCA<<endl;
				return;
			}
		}
	}
	
}
signed main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0);cout.tie(0);
	solve();
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值