牛客练习赛 40

A. 膜拜华哥。。。。简直神仙 dp.... 

这道题dp 思路解决, dp [ n ] [ i ] [ j ] 代表 n 长度排列, 以第 i 号音符作为开头, j 号音符作为结尾

那么有 

dp [ n ] [ i ] [ j ]  = \sum dp[ n - 1 ] [ k ] [ i ] (  1 <= k <= 49 ) 同时还要保证 k, i, j 这个排列是合法的,

开个三维 vis 记录非法排列就好了,最后结果就是

\sum \sum dp[n]][i][j] ( 1<= ( i , j ) <=n)

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
#define ll long long int
const ll mod = 1e9+7;
ll dp[505][55][55],vis[55][55][55];
int main()
{
    ll n,q; cin>>n>>q;
    for(int i=1;i<=q;i++)
    {
        ll a,b,c; cin>>a>>b>>c;
        vis[a][b][c] = 1; vis[a][c][b] = 1;
        vis[b][a][c] = 1; vis[b][c][a] = 1;
        vis[c][a][b] = 1; vis[c][b][a] = 1;
    }
    for(int i=1;i<=49;i++)
		for(int j=1;j<=49;j++)
			dp[2][i][j]=1;
    for(int i=2;i<=n;i++)
    {
        for(int a=1;a<=49;a++)
            for(int b=1;b<=49;b++)
                for(int c=1;c<=49;c++)
                if(vis[a][b][c] == 0)
                {
                    dp[i+1][b][c] = (dp[i+1][b][c] + dp[i][a][b])%mod;
                }
    }
    ll sum = 0;
    for(int i=1;i<=49;i++)
        for(int j=1;j<=49;j++)
        sum=(sum+dp[n][i][j])%mod;
    cout<<sum<<endl;
    return 0;
}

C. 把题干改成人话就是如何在走过每一条最多2次的情况下遍历整棵树

那么我们直接求 带权树直径,直径只走一次,其他走两次

总长度减去一条直径就完事了。

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=2000005;
long long n,m,t,p,ans,sum;
struct edge{int to,nxt,w;}ed[N];
long long d[N],head[N];
void add(long long x,long long y,long long z)
{
	ed[++t].nxt=head[x];head[x]=t;
	ed[t].to=y; ed[t].w=z;
}
void dfs(long long x,long long father)
{
	if(ans<d[x]){ ans=d[x];p=x; }
	for(int i=head[x];i;i=ed[i].nxt)
	{
		int t = ed[i].to;
		if(t==father) continue;
		d[t]=d[x]+ed[i].w;
		dfs(t,x);
	}
}
void dfs1(long long x)
{
	ans=0; d[x]=0;
	dfs(x,0);
}
int main()
{
	long long x,y,z;
	scanf("%lld",&m);
	for(int i=1;i<m;++i)
	{
		scanf("%lld%lld%lld",&x,&y,&z);
		sum+=z;
		add(x,y,z); add(y,x,z);
	}
	dfs1(1); dfs1(p);
	printf("%lld",sum*2-ans);
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值