牛客练习赛105(A切蛋糕的贝贝、B抱歉,这没有集美、D点分治分点)

A切蛋糕的贝贝

题目链接

关键点:

1、题目已经定下来了切的块数,即六块,且比例为1:1:4:5:1:4,那么只有刚刚好为题目要求的比例的倍数,才可以切。1+1+4+5+1+4 = 16,即为16的倍数的边形才可以满足要求,其他一律不行,

2、且一共切成6块,根据题目要求的切法,最少也要切5次

# include <bits/stdc++.h>
using namespace std;
int n;
int main()
{
    cin>>n;
    if (n%16 == 0)
    {
        cout<<"5"<<endl;
    }
    else
        cout<<"-1"<<endl;
    
    
    return 0;
}

B抱歉,这没有集美

题目链接

关键点:

1、可以发现要是序列的排序和其所分配的号至少要出现一个公倍数为偶数,那么至少要有一个偶数在偶数位,直接这样求很麻烦,反过来我们可以求所有的奇数在偶数位的情况数,然后将总数的全排列个数减去该数即可

2、又可以发现,设人数为n,则奇数在偶数位的情况数为n的全排列 - ((n+1)*n/2)的全排列

即nd的全排列 - (奇数个数在偶数位上的排列和*((n - 偶数位)的全排列))

比方说人数为5,则奇数个数为3,偶数位为2,5的全排列 - A(上2下3)*A(上3下3)

不会打数学符号。。。

完整代码:

# include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD = 1e9+7;
ll sum1 = 1, sum2 = 1, num;
int n;
int ji, ou;
int main()
{
    cin>>n;
    for (int i=1; i<=n; i++)
        sum1 = sum1*i%MOD;
    for (int i=1; i<=(n+1)/2; i++)
        sum2 = sum2*i%MOD;
    sum2 = sum2*sum2%MOD;
    num = (sum1-sum2+MOD)%MOD;
    cout<<num<<endl;
    return 0;
}

D点分治分点

题目链接

关键点:

1、首先要理解题目中有关简单路径的定义:即从起点到终点的所有路径长度的最小值

d(u,v) = max(u->v的最短路径);

2、那么我们可以将简单路径作为路径长度,来求最长的d

3、题目中说明了可能存在的重边和自环,那么就用迪杰斯特拉算法,求最长路径

4、将最小堆改为利用最大堆,并且有关路径更新的要求也不同,可以发现,求出两点的d值,后序再次经过时,其d值也会受先前的d值影响,那么就可以用来更新

定义low[x],为起点到x的最小路径长度

min(low[tmp.x], edge[i].len)>d[y]

满足要求,就更新low值和d值

完整代码:

# include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct ty1{
    ll t, len, next;
}edge[100000+10];
struct ty2{
    ll x, low;
    bool operator < (const ty2& a)const{
        return low<a.low;
    }
};
priority_queue<ty2>q;
ll d[100000+10], vis[100000+10], head[100000+10], low[100000+10];
int n, m, s, cnt;
void addedge(int x, int y, int len)
{
    edge[++cnt].t = y;
    edge[cnt].len = len;
    edge[cnt].next = head[x];
    head[x] = cnt;
}
void dij()
{
    memset(d, -1, sizeof(d));
    memset(vis, 0, sizeof(vis));
    ty2 tmp;
    tmp.low = 1000000000+10, tmp.x = s;
    low[s] = 1000000000+10;
    q.push(tmp);
    while (!q.empty())
    {
        ty2 tmp = q.top();
        q.pop();
        if (vis[tmp.x]) continue;
        vis[tmp.x] = 1;
        for (int i=head[tmp.x]; i!=-1; i=edge[i].next)
        {
            int y = edge[i].t;
//             cout<<edge[i].len<<endl;
            if (min(low[tmp.x], edge[i].len)>d[y])
            {
//                 cout<<"123"<<endl;
                d[y] = min(low[tmp.x], edge[i].len);
                low[y] = d[y];
                ty2 tmp;
                tmp.x = y, tmp.low = d[y];
                q.push(tmp);
            }
        }
    }
}
int main()
{
    cin>>n>>m>>s;
    memset(head, -1, sizeof(head));
    for (int i=1; i<=m; i++)
    {
        int x, y, len;
        cin>>x>>y>>len;
        addedge(x, y, len);
    }
    dij();
    for (int i=1; i<=n; i++)
    {
        if (i == s)
            cout<<"-1 ";
        else
        cout<<d[i]<<" ";
    }
    
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值