牛客练习赛40

A题:https://ac.nowcoder.com/acm/contest/369/A

题目描述

"我明白。"

作为这命运剧场永远的观众,小D一直注视着这片星光璀璨的舞台,舞台上,少女们的身姿演绎出了一幕幕动人的场景,令人回味无穷。

有的时候,小D也会自己写一些歌曲,来加入Starlight的剧本,使得剧本充满了新的生命力。

现在小D又要准备写乐谱了,小D写谱的方式比较独特。他会先写出一个按照音符出现顺序排成的序列,再进一步整合,每次整合会选取相邻的三个作为三和弦。整合次数无限。

小D选取的音符形如D5 F6这种形式,例如D5表示D大调sol(这里不考虑升降音)为了方便生成乐谱,他将这些音符进一步转化了,小D给C D E F G A B重新编号成了1 2 3 4 5 6 7,之后新的音符编号生成方式应为(字母对应的标号-1)*7+数字,例如

但小D讨厌一些他所认为的不优美的和弦,因此他并不希望自己的谱子里面有可能出现这样的三和弦,也就说音符组成的序列里不应该存在他所讨厌的子段,假如C5 F1 A2这三个音符凑成的和弦小D不喜欢,那么序列里面就不能出现C5 F1 A2,C5 A2 F1,A2 C5 F1,A2 F1 C5,F1 A2 C5,F1 C5 A2这六种子段。

现在小D正在推算有多少合法的序列,答案对  取模。

星屑飘洒的舞台上,可人绽放的爱之花,请努力让大家星光闪耀吧!

暴力dp.....,窝还需多写题目鸭。dp[i][j][k]表示已经在第i位了并且后两位的数字为j,k的方案数。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mod 1000000007
ll can[51][51][51],dp[501][51][51];
int n,q;
int  main()
{
    for(int i=0;i<50;i++){
        for(int j=0;j<50;j++){
            for(int k=0;k<50;k++){
                can[i][j][k]=1;
            }
        }
    }
    scanf("%d %d",&n,&q);
    int xx,yy,zz;
    for(int e=1;e<=q;e++){
        scanf("%d %d %d",&xx,&yy,&zz);
        can[xx][yy][zz]=can[xx][zz][yy]=can[yy][xx][zz]=can[yy][zz][xx]=can[zz][xx][yy]=can[zz][yy][xx]=0;
    }
    dp[0][0][0]=1;
    for(int i=1;i<=n;i++){
        for(int j=0;j<50;j++){
            for(int k=0;k<50;k++){
                for(int l=1;l<50;l++){
                    dp[i][k][l]=(dp[i][k][l]+can[j][k][l]*dp[i-1][j][k])%mod;
                }
            }
        }
    }
    ll ans=0;
    for(int i=1;i<50;i++){
        for(int j=1;j<50;j++){
            ans+=dp[n][i][j];
            ans%=mod;
        }
    }
    printf("%lld\n",ans%mod);
    return 0;
}

C题:https://ac.nowcoder.com/acm/contest/369/C

小A给你了一棵树,对于这棵树上的每一条边,你都可以将它复制任意(可以为0)次(即在这条边连接的两个点之间再加一条边权相同的边),求所有可能新形成的图中欧拉路的最短长度

欧拉路:从图中任意一个点开始到图中任意一个点结束的路径,并且图中每条边只通过恰好一次

答案即为所有边权的两倍和减去树的直径,注意边权加和时要用long long。

官方题解:

先考虑回路的情况。由于是一棵树,任两点间路径只有一条,从一条边走到深度更大的点,一定还会从同一条边返回以回到起点或者遍历其他子树,所以每条边需要复制一次,此时答案是边权和的两倍。

不是回路的情况可以减掉从终点回到起点的路径,要让这条路径尽量长,所以长度一定是直径的长度。

#include <bits/stdc++.h>
using namespace std;
int n;
typedef long long ll;
const int N=222222;
ll dist[N];
vector < pair<int,ll> >edge[N];
void dfs(int u,int fa,ll p)
{
    dist[u]=p;
    for(auto &it: edge[u]){
        if(it.first!=fa){
            dfs(it.first,u,p+it.second);
        }
    }
}

int main()
{
    scanf("%d",&n);
    int u,v;
    ll ans=0,w;
    for(int i=1;i<n;i++){
        scanf("%d %d %lld",&u,&v,&w);
        edge[u].push_back(make_pair(v,w));
        edge[v].push_back(make_pair(u,w));
        ans+=(w*2);
    }
    dfs(1,0,0);
    int U=max_element(dist+1,dist+n+1)-dist;
    dfs(U,0,0);
    ll d=*max_element(dist+1,dist+n+1);
    ans-=d;
    printf("%lld\n",ans);
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值