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
  • 相关阅读:
    Eclipse 导入项目乱码问题(中文乱码)
    sql中视图视图的作用
    Java基础-super关键字与this关键字
    Android LayoutInflater.inflate(int resource, ViewGroup root, boolean attachToRoot)的参数理解
    Android View和ViewGroup
    工厂方法模式(java 设计模式)
    设计模式(java) 单例模式 单例类
    eclipse乱码解决方法
    No resource found that matches the given name 'Theme.AppCompat.Light 的完美解决方案
    【转】使用 Eclipse 调试 Java 程序的 10 个技巧
  • 原文地址:https://www.cnblogs.com/mogeko/p/11738016.html
Copyright © 2011-2022 走看看