2019 计蒜之道 初赛 第一场

北京市商汤科技开发有限公司面向青少年研发了一款智能伴游机器人-- AI 伴游小精灵。一经推出,深受孩子们的喜爱,可爱又机智的小精灵会想出很多有趣的小游戏来启迪孩子们思考。今天,小精灵给你提出了一个神奇又有趣的多米诺骨牌小游戏。

你手上有一副神奇的多米诺骨牌,数量有 nn个,编号为 1 \sim n1∼n。它们之间存在着 n-1n−1 个单向推倒关系,即推倒 xx 会导致 yy 也被推倒,而且这样的关系都满足 x<yx<y,且每组关系中的 yy 不会重复。

一开始只有 11 号骨牌不会被其他骨牌推倒,所以你只需要推倒 11 号骨牌就可以推倒所有的骨牌。

小精灵给你提的问题是:如果我们允许去掉 22 个骨牌,那么在最坏情况下你最少需要推倒几个骨牌才能使所有骨牌倒下?

输入格式

第一行输入一个整数 nn,表示有 nn 个多米诺骨牌。

接下来有 n-1n−1 行的输入,每行输入两个整数 x,yx,y,表示推倒 xx 会导致 yy 也被推倒。

输出格式

输出一个整数表示去掉两个骨牌之后,最坏情况下你最少需要推倒几个骨牌才能使所有骨牌倒下。

数据规模

n \le 5 \times 10^3n≤5×103

样例输入复制

7
1 2
1 3
1 5
2 4
4 7
4 6

样例输出复制

5

思考:找出最大两个度的结点,度之和等于等于需要推到的次数,如果结点相邻,结果需要减一

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e3+50;
int n;
vector<int>out[maxn];
int in[maxn];
bool vis[maxn];

void Update()
{
    int t=0;
    for(int i=1;i <= n;++i)
    {
        if(vis[i] || out[i].size() < out[t].size())
            continue;

        if(t == 0)
            t=i;
        if(out[i].size() > out[t].size() || in[i] > 0)
            t=i;
    }
    for(int i=0;i < out[t].size();++i)
        in[out[t][i]]--;
    vis[t]=true;
}
int Solve()
{
  
    if(n <= 2)
        return 0;
    Update();
    Update();
    int ans=0;
    for(int i=1;i <= n;++i)
        if(!vis[i] && in[i] == 0)
            ans++;
    return ans;
}
int main()
{
    cin>>n;
    for(int i=1;i < n;++i)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        out[x].push_back(y);
        in[y]++;
    }
    printf("%d\n",Solve());

    return 0;
}

北京市商汤科技开发有限公司建立了新的 AI 人工智能产业园,这个产业园区里有 nn 个路口,由 n - 1n−1 条道路连通。第 ii 条道路连接路口 u_iui​ 和 v_ivi​。

每个路口都布有一台信号发射器,信号频段是 11 到 mm 之间的一个整数。

道路所连接的两个路口的发射信号叠加可能会影响道路的正常运行。具体地,如果第 ii 条道路连接的两个路口发射信号的频段分别为 aa 和 bb,那么 \gcd(a, b)gcd(a,b) 不能恰好等于道路的保留频段 w_iwi​。每条道路的保留频段是唯一的,即不会与其余任何道路的保留频段相同。

你现在需要确定每个路口发射信号的频段,使其符合要求。

在开始之前,你想先算出共有多少种合法的方案。

由于答案可能很大,输出对 10 ^ 9 + 7109+7 取模的值作为答案。

输入格式

第一行,两个正整数 n, mn,m 分别代表路口数量和信号频段上限。

接下来 n - 1n−1 行,每行描述一条道路。第 ii 行有三个整数 u_i, v_i, w_iui​,vi​,wi​ 意义如上所述。

保证 1 \le n \le m, 1 \le u_i, v_i \le n, 1 \le w_i \le m1≤n≤m,1≤ui​,vi​≤n,1≤wi​≤m。

输出格式

输出一个整数,代表合法方案的数量对 10 ^ 9 + 7109+7 取模的值。

数据范围

  • m \le 50m≤50
  • v_i = u_{i + 1} = u_i + 1vi​=ui+1​=ui​+1 (1 \le i \lt n)(1≤i<n)

样例解释

所有合法的方案为 (2, 2, 1), (2, 2, 3), (3, 3, 1), (3, 3, 2), (3, 3, 3)(2,2,1),(2,2,3),(3,3,1),(3,3,2),(3,3,3)。

样例输入复制

3 3
1 2 1
2 3 2

样例输出复制

5

思考,使用dp,   递推关系:f(i,j)=\sum(gcd !=wi)+f(i-1,k) ,f(i,j)表示第i个路口的j种方案

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
ll P = 1000000007;
ll dp[100][100];
int gcd(int a, int b)
{
    if (b == 0) return a;
    return gcd(b, a % b);
}
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    int w[100];
    for (int i = 1; i <= n - 1; i++)
    {
        int u, v;
        scanf("%d%d%d", &u, &v, &w[i]);
    }
	
    for (int i = 1; i <= m; i++)
    {
        dp[1][i] = 1;
    }
    for (int i = 2; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            for (int k = 1; k <= m; k++)
            {
                
                if (gcd(j, k) != w[i - 1])
                {
                    dp[i][j] += dp[i - 1][k];
                    dp[i][j] %= P;
                }
            }
        }
    }
    
    ll ans = 0;
    for (int i = 1; i <= m; i++)
    {
        ans += dp[n][i];
        ans %= P;
    }
    cout << ans << endl;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Aurora_U

谢谢你的鼓励,我会继续努力!

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

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

打赏作者

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

抵扣说明:

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

余额充值