zoukankan      html  css  js  c++  java
  • Luogu T104509 MC

    传送门(已毁)

    老板的题qaq

    题目描述

    n 个星球,有 m 条星球与星球之间的双向航道。(莫得航道的两个星球不可互相到达)

    可以进行如下操作:

    生成 Ti 个生物到一个星球 Xi,并给定这些生物的智商程度 Yi

    破坏一条航道,航道编号为 Si

    询问给定的一个星球 Xi ,从 Xi 出发可以到达的所有星球中选择 Ni 个生物,使得他们的智商程度都为 Yi的概率为多少,对 19260817 数取模。

    输入数据不保证没有重边和自环,不保证同一条边不会被切断两次以上。

    输入格式

    第一行三个正整数 n,m,q

    接下来 n 行,每行两个正整数 Ti , Yi ,分别代表第 ii 个星球初始生物数和智商程度

    接下来 m 行,每行两个正整数 Xi , Yi ,分别代表这条道路的起点和终点

    接下来 q 行,每行第一个正整数 opt(1opt3)

    当 opt=1 时,表示添加生物,输入三个整数 Xi , Ti , Yi

    当 opt=2时,表示删除航道,输入一个整数 Xi

    当 opt=3 时,表示询问,输入三个整数 Xi , Ni , Yi

    输出格式

    对于每一个 opt=3 的操作,输出一行一个整数。

    说明/提示

    对于 30% 的数据,1n,m,q100

    对于 60% 的数据, 1n,m,q50000

    对于 100% 的数据,1n,m,q400000

    对于 100% 的数据,保证所有生物的智商 N

    对于 100% 的数据,保证每次添加的人数和初始人数都不超过10

    对于 100% 的数据,保证数据随机生成

     

    时间限制 3.00s
    内存限制 500.00MB

    这题思路的话大概20多分钟…

    1.求概率

    比如选3个,可选的有9个,一共有20个,结果就是9/20 * 8/19 * 7/18,

    化简一下就是(9!/6!)/(20!/17!)

    所以...预处理一下阶乘,取模用费马小定理求逆元即可

    *注意:fac[0] = 1

    毕竟可能有除0的情况...或者说,取0的时候没办法求逆元。

    2.维护修改

    无向图,连通就行,那就并查集qwq?

    因为只有删边没有加边,可以离线…

    先把所有没删的边连上(注意要忽略删除两次的),增加生物的操作都加上

    然后倒序枚举的时候,加生物→减生物,删边→加边(并查集合并)

    最后再正序输出答案就行了

    3.维护生物个数

    不会用map...直接数组(w[i][j]:i星球j生物个数)就TLE+MLE

    复杂度...O(能过) (毕竟数据全随机嘛qaq)

    void merge(int x,int y) {
        x = getfa(x),y = getfa(y);
        if(x == y) return;
        if(w[x].size() > w[y].size()) swap(x,y);
        fa[x] = y;
        for(map<int,int>::iterator i = w[x].begin(); i != w[x].end(); i++)
            w[y][(*i).first] += (*i).second;
        sum[y] += sum[x];
    }

    map写起来和数组差不多,for循环改一下就行了。还方便启发式合并(.size())!

    遍历的时候用迭代器(注意迭代器不能写 <=.end(),只能写 !=.end() )

    然后比如 m[a] = x,i是迭代器,(*i).first就是a,(*i).second就是x

    也就是m[(*i).first] = (*i).second

    debug:

    1.n和q写反了...

    2.f[0] = 1

    代码如下

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<map>
    #define MogeKo qwq
    #define Darcy amour
    using namespace std;
    
    const int maxn = 4e5+10;
    const int mod = 19260817;
    int n,m,q,x,y;
    int fa[maxn],op[maxn];
    long long a[maxn],b[maxn],t[maxn],ans[maxn];
    long long sum[maxn],f[maxn*10+10];
    bool del[maxn];
    map <int,int> w[maxn];
    
    struct edge {
        int l,r;
    } e[maxn];
    
    int getfa(int x) {
        if(fa[x] == x) return x;
        return fa[x] = getfa(fa[x]);
    }
    
    void init() {
        for(int i = 1; i <= n; i++)
            fa[i] = i;
    }
    
    void merge(int x,int y) {
        if(x == y) return;
        x = getfa(x);
        y = getfa(y);
        if(x == y) return;
        if(w[x].size() > w[y].size()) swap(x,y);
        fa[x] = y;
        for(map<int,int>::iterator i = w[x].begin(); i != w[x].end(); i++)
            w[y][(*i).first] += (*i).second;
        sum[y] += sum[x];
    }
    
    void getfac() {
        f[0] = 1;
        f[1] = 1;
        for(int i = 2; i <= maxn*10; i++)
            f[i] = ((long long)(f[i-1]%mod)*(i%mod))%mod;
    }
    
    long long qpow(int a,int b) {
        long long ans = 1,base = a;
        while(b) {
            if(b&1) (ans *= base) %= mod;
            (base *= base) %= mod;
            b >>= 1;
        }
        return ans%mod;
    }
    
    long long inv(int x) {
        return qpow(x,mod-2)%mod;
    }
    
    int calc(int x,int y,int k) {
        if(w[x][y] < k) return 0;
        long long p = f[w[x][y]] * inv(f[w[x][y]-k]) % mod;
        long long q = f[sum[x]] * inv(f[sum[x]-k]) % mod;
        return p*inv(q)%mod;
    }
    
    int main() {
        scanf("%d%d%d",&n,&m,&q);
        init();
        getfac();
        for(int i = 1; i <= n; i++) {
            scanf("%d%d",&x,&y);
            w[i][y] += x;
            sum[i] += x;
        }
        for(int i = 1; i <= m; i++)
            scanf("%d%d",&e[i].l,&e[i].r);
    
        for(int i = 1; i <= q; i++) {
            scanf("%d%lld",&op[i],&a[i]);
            if(op[i] == 1) {
                scanf("%lld%lld",&t[i],&b[i]);
                w[a[i]][b[i]] += t[i];
                sum[a[i]] += t[i];
            }
            if(op[i] == 2) {
                if(!del[a[i]])
                    del[a[i]] = true;
                else op[i] = 0;
            }
            if(op[i] == 3)
                scanf("%lld%lld",&t[i],&b[i]);
        }
    
        for(int i = 1; i <= m; i++)
            if(!del[i])
                merge(e[i].l,e[i].r);
    
        for(int i = q; i >= 1; i--) {
            if(op[i] == 1) {
                x = getfa(a[i]);
                w[x][b[i]] -= t[i];
                sum[x] -= t[i];
            }
            if(op[i] == 2)
                merge(e[a[i]].l,e[a[i]].r);
            if(op[i] == 3) {
                x = getfa(a[i]);
                ans[i] = calc(x,b[i],t[i]);
            }
        }
        for(int i = 1; i <= q; i++)
            if(op[i] == 3)
                printf("%lld
    ",ans[i]);
        return 0;
    }
    View Code
  • 相关阅读:
    新零售解决方案体系架构
    设计模式-分类
    设计模式-设计原则
    一天一个 Linux 命令(12):tree 命令
    RabbitMQ中如何保证消息的可靠传输?如果消息丢了怎么办
    为什么使用MQ?
    一天一个 Linux 命令(11):cp命令
    数据结构和算法-线性查找-二分查找
    作图工具汇总
    Git 命令大全,Git命令汇总,Git命令说明
  • 原文地址:https://www.cnblogs.com/mogeko/p/11738016.html
Copyright © 2011-2022 走看看