每日一题4.26-4.30

4.26比赛(枚举+DFS)

NC14734

题目大意:给出12道题做出的概率,问做出0-12道题目的概率

/*

4.26 比赛 :https://ac.nowcoder.com/acm/problem/14734 

对于每一个题目要么做出,要么做不出,利用dfs进行判断即可 
 // 还有一种dp做法,未完待续......

*/ 

#include<bits/stdc++.h>

using namespace std;

const int N  = 15;

double a[N], b[N], c[N], un[N];
double ans;


void dfs(int pos, int now, int need, double p)  
{
    if(pos == 13) // 当所有题目都写完了 
    {
        if(now == need) { // 达到了需要 
            ans += p;
        }
        return ;
    }  // 判断该题做不做出来 
    if(now < need )
        dfs(pos + 1, now + 1, need, p * (1 - un[pos]));  
    dfs(pos + 1, now, need, p * un[pos]);
}

int main()
{
    for (int i = 1; i <= 12; ++i) cin >> a[i];
    for (int i = 1; i <= 12; ++i) cin >> b[i];
    for (int i = 1; i <= 12; ++i) cin >> c[i];
 	// 一道题做不出来:自己做不出,没听到左边也没听到右边 
    for (int i = 1; i <= 12; ++i) un[i] = (1-a[i]) * (1-b[i]) * (1-c[i]);

    for (int i = 1; i <= 13; ++i)
    {
        ans = 0;
        dfs(1, 0, i - 1, 1);
        printf("%.6f\n", ans);
    }

    return 0;
}

4.27滑雪与时间胶囊(BFS+Kruskal)

SCOI2012

思路:

最小生成树
首先利用BFS求出连通图,然后用Kruskal算法求出最小树
// 未完待续:Prim
代码:

/*
Problem : 给出n个景点,m个边连接各个景点,求出最多景点的最短距离

Solution :BFS求连通图,Kruskal求最小生成树

*/

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

// 快读模板
inline int read() 
{
    int s = 0, w = 1; char ch = getchar();
    while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); }
    while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    return s * w;
}


// 数据范围
const int Max = 1e6 + 10;
int n, m, h[Max];
int head[Max], tot; // 链式前向星存图;

struct node{
    int u, v, w, next;

    bool operator < (const node& b)const{
        if(h[v] == h[b.v]) return w < b.w;//高度相同的时候,边权升序
        return h[v] > h[b.v]; // 高度降序
    }
}edge[Max<<1];

int vis[Max], p[Max]; // 记录结点是否在图中。并查集数组
ll cnt, sum; // 结点个数及权值

void add(int u, int v, int w) // 增加一条u->v边权为w的边
{
    tot++;
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot;
}

//并查集find函数
int find(int x)
{
    if(p[x] != x) p[x] = find(p[x]);
    return p[x];
}

void BFS(int x) // BFS求出连通图
{
    queue<int>Q;
    Q.push(x);
    vis[x] = 1;
    cnt ++;
    while(Q.size())
    {
        int u = Q.front();
        Q.pop();
        for (int i = head[u]; i ; i = edge[i].next)
        {
            int v = edge[i].v;
            if(!vis[v]) // 没用过
            {
                Q.push(v);
                cnt ++;
                vis[v] = 1;
            }
        }
    }
}

void Kruskal() // 求出最小生成树
{
    sum = 0;
    for (int i = 1; i <= n; ++i) p[i] = i; // 初始化并查集
    for (int i = 1; i <= tot; ++i)
    {
        int u = edge[i].u, v = edge[i].v, w = edge[i].w;
        if(vis[u] && vis[v]) // 这两个点都在图中
        {
            if(find(u) != find(v)) // 并且不在一个集合里面
            {
                p[find(u)] = find(v); // 将这两个集合合并
                sum += w;  // 权值增加
            }
        }
    }
}

int main()
{
    n = read();
    m = read();
    memset(h, 0, sizeof h);
    for (int i = 1; i <= n; ++i) h[i] = read();
    int u, v, w;
    memset(head, 0, sizeof head);
    tot = 0;
    for (int i = 1; i <= m; ++i)
    {
        u = read();
        v = read();
        w = read();
        if(h[u] >= h[v]) add(u, v, w);
        if(h[u] <= h[v]) add(v, u, w);
    }
    BFS(1);
    sort(edge+1, edge+1+tot); // 高度降序,边权升序
    Kruskal();
    cout << cnt << ' ' << sum << endl;
    return 0;
}

4.28储物点的距离(前缀和)

NC14683

首先对距离进行前缀和预处理,然后需将每个点的数量进行前缀和处理,最后要另外开一个数组表示到1的花费

The most important tips: 减法的取模

a - b 对 c 取模
Answer :  ( a - b + c ) % c;
  • 然后就是对x的三种情况的分类讨论

在这里插入图片描述

AC代码:

#include<bits/stdc++.h>

using namespace std;

const int N = 200010, mod = 1e9 + 7;
typedef long long ll;

ll a[N], b[N], sum[N];

ll n, m;
ll x, l , r;

int main()
{
    scanf("%lld%lld", &n, &m);
    for (int i = 2; i <= n; ++i) scanf("%lld", &a[i]), a[i] = (a[i - 1] + a[i]) % mod;
    for (int i = 1; i <= n; ++i){
        scanf("%lld", &b[i]);
        sum[i] = (sum[i - 1] + a[i] * b[i]) % mod;
        b[i] = (b[i - 1] + b[i] ) % mod;
    }
    ll ans;
    while( m -- )
    {
        ans  = 0;
        scanf("%lld%lld%lld", &x, &l, &r);
        if(x <= l)
        {
            ans = (sum[r] - sum[l - 1] + mod) % mod;
            ans = (ans - ((b[r]  - b[l - 1] + mod) % mod * a[x] % mod) + mod) % mod;
        }
        else if(r <= x)
        {
            ans = ((b[r] - b[l - 1] + mod ) % mod * a[x] % mod) % mod;
            ans = (ans - ((sum[r] - sum[l - 1 ]) + mod) % mod  + mod)% mod;
        }
        else 
        {
            // [l, x] + [x, r]
            ans = (sum[r] - sum[x - 1] + mod) % mod;
            ans = (ans - ((b[r] - b[x - 1] + mod) % mod * a[x] % mod) + mod) % mod; 
            ans += ((b[x] - b[l - 1] + mod) % mod * a[x] % mod ) % mod;
            ans = (ans - ((sum[x] - sum[l - 1]) + mod) % mod + mod) % mod;
        }
        cout << ans << endl;
    }
    return 0;
}

4.29中位数图(思维)

NC19913

思路: 找出b的位置,并且把大于b的标记为1,小于1的标记为-1,然后再pos位置往两边判断,当sum为的时候表示有一个答案,然而对于两边的情况,利用一个数组记录左边的情况,当右边有与之对应的时候,答案加一

代码:

/*
Solution:对于序列中位数,大于他的数一定等于小于他的数

ps:单独的自己也算

*/
#include<bits/stdc++.h>

using namespace std;

const int Max = 100010;
int n, b, a[Max], num[Max<<1]; // a[i] 原数组,num[i] 表示一边的情况


int main()
{
    scanf("%d%d", &n, &b);
    int pos, x;
    for (int i = 1; i <= n; ++i) // 将大于标记为1, 小于标记为-1,
    {                            // 并把b的位置pos找出来
        scanf("%d", &x);
        if(x > b) a[i] = 1;
        else if(x < b) a[i] = -1;
        else pos = i;
    }
    int sum = 0, ans = 1; // 对pos的左边进行寻找,并且记录左边的大小情况
    for (int i = pos - 1; i >= 1; --i)
    {
        sum += a[i];
        num[n - sum] ++;
        if(!sum) ans ++;
    }
    sum = 0; // 将sum初始化,开始右边的判断,如果在左边有相对应的的大小情况答案加一
    for (int i = pos + 1; i <= n; ++i)
    {
        sum += a[i];
        ans += num[n + sum];
        if(!sum) ans ++;
    }
    cout << ans << endl;
    return 0;
}

4.30codeJan与旅行(暴力+思维)

NC14844

思路: 要在n座城市中访问m次,求最短路径,答案一定是在某两个城市之间一直来回,
假设从p走到第i座城市,然后是在i与i+1座城市之间来回答案为: abs(p-a[i]+num*(a[i+1]-a[i])
有特殊情况为,可以先走另外一边然后在执行前面的方案,答案为:
abs(p-a[i]) + (num-1)*(a[i+1]-a[i]) + abs(a[pos] - p)*2;
Hack数据:
1
3 10 2
1 10 14

AC代码:

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
ll a[100010];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while(t -- )
    {
        int n, m, p;
        cin >> n >> m >> p;
        int pos = 0;
        for (int i = 1; i <= n; ++i){
            cin >> a[i];
            if(a[i] < p) pos = i; // 接近p的城市
        }
        ll ans = 1e18;
        for (int i = 1; i < n; ++i)
        {
            if(i <= pos){ // 左边
                if(pos - i + 1 > m) continue;
                ll num = m - (pos - i + 1), dist = p - a[i];
                ans = min(ans, dist + num * (a[i+1] - a[i]));
                if(num > 0 && pos + 1 <= n)
                    ans = min(ans, (a[pos+1] - p) * 2 + dist + (num-1)*(a[i+1]-a[i]));
            }
            else {
                if(i - pos > m) continue;
               ll num = m - (i - pos), dist = a[i] - p;
                ans = min(ans, dist + num * (a[i+1]-a[i]));
                if(num > 0 && pos >= 1)
                    ans = min(ans, (p - a[pos])*2 + dist + (num-1)*(a[i+1]-a[i]));
            }
        }
        cout << ans << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

W⁡angduoyu

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值