zoukankan      html  css  js  c++  java
  • fzyzojP3580 -- [校内训练-互测20180315]小基的高智商测试

    题目还有一个条件是,x>y的y只会出现一次(每个数直接大于它的只有一个)

    n<=5000

     [HNOI2015]实验比较 的加强版

    g(i,j,k)其实可以递推:g(i,j,k)=g(i-1,j,k-1)+g(i,j-1,k-1)+g(i-1,j-1,k-1)

     

     代码:

    判断无解的时候可能比较混乱

    1.先保证不要连有向重边

    2.如果不是树形图,就是有环,vis过了

    #include<bits/stdc++.h>
    #define il inline
    #define reg register int
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    il void rd(int &x){
        char ch;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    namespace Miracle{
    const int N=5005;
    const int mod=1e9+7;
    int jie[N],inv[N];
    int n,m;
    int qm(int x,int y){
        int ret=1;
        while(y){
            if(y&1) ret=(ll)ret*x%mod;
            x=(ll)x*x%mod;
            y>>=1;
        }
        return ret;
    }
    int C(int n,int m){
        return (ll)jie[n]*inv[m]%mod*inv[n-m]%mod;
    }
    struct node{
        int nxt,to;
    }e[2*N];
    int hd[N],cnt;
    int du[N];
    bool fl;
    void add(int x,int y){
    //    cout<<" x to y "<<x<<" "<<y<<endl;
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;
        hd[x]=cnt;
    }
    int fa[N];
    struct con{
        int x,y;
        int typ;//1:x<y 2:x=y 3:x>y
    }q[N];
    map<pair<int,int>,int>mp,con;
    int fin(int x){
        return fa[x]==x?x:fa[x]=fin(fa[x]);
    }
    int f[N][N];
    int mo(int x){
        return x>=mod?x-mod:x;
        //return x%mod;
    }
    bool vis[N];
    void dfs(int x,int ff){
    //    cout<<" x ff "<<x<<" "<<ff<<" fl "<<fl<<endl;
        if(!fl) return;
        int son=0;
        if(vis[x]) {
            fl=false;return;
        }
        vis[x]=1;
        for(reg i=hd[x];i;i=e[i].nxt){
            if(!fl) return;
            int y=e[i].to;
            ++son;
            dfs(y,x);
        }
        if(son){
            for(reg j=1;j<=n;++j){
                f[x][j]=1;
            }
            for(reg i=hd[x];i;i=e[i].nxt){
                int y=e[i].to;
                for(reg j=1;j<=n;++j){
                    f[x][j]=(ll)f[x][j]*f[y][j-1]%mod;
                }
            }
            for(reg j=1;j<=n;++j){
                f[x][j]=mo(f[x][j]+f[x][j-1]);
            //    printf("f[%d][%d] : %d
    ",x,j,f[x][j]);
            }
        }else{
            for(reg i=1;i<=n;++i) f[x][i]=i;
        }
    }
    int main(){
        rd(n);rd(m);
        char ch[233];
        for(reg i=0;i<=n;++i){
            fa[i]=i;
        }
        fl=true;
        for(reg i=1;i<=m;++i){
            rd(q[i].x);
            scanf("%s",ch);
            rd(q[i].y);
            if(ch[0]=='>') q[i].typ=3;
            else{
                int k1=fin(q[i].x),k2=fin(q[i].y);
                q[i].typ=2;
                fa[k1]=k2;
            }
        }
        for(reg i=1;i<=m;++i){
            if(!fl) break;
        //    cout<<q[i].x<<" "<<q[i].y<<" "<<q[i].typ<<endl;
            int k1=fin(q[i].x),k2=fin(q[i].y);
    //        if(!che(k1,k2,q[i].typ)) fl=false;
    //        cmp[k1][k2]=q[i].typ;
    //        cmp[k2][k1]=4-q[i].typ;
            
            if(q[i].typ==3){
                if(mp[make_pair(k1,k2)]==0){
                    add(k1,k2);
                    mp[make_pair(k1,k2)]=1;
                }
                ++du[k2];
            }else if(q[i].typ==1){
                if(mp[make_pair(k2,k1)]==0){
                    add(k2,k1);
                    mp[make_pair(k2,k1)]=1;
                }
                ++du[k1];
            }
        }
        if(!fl){
        //    cout<<" no "<<endl;
            puts("0");return 0;
        }
        for(reg i=1;i<=n;++i){
            if(fin(i)==i&&du[i]==0){
                add(0,i);
            }
        }
    //    cout<<" fl "<<fl<<endl;
        ++n;//warning!! 0~n-1
        dfs(0,-1);
    
        for(reg i=0;i<=n-1;++i){
            if(!vis[fin(i)]) fl=false;
        }
        if(!fl){
        //    cout<<" no "<<endl;
            puts("0");return 0;
        }
        jie[0]=1;
        for(reg i=1;i<=n;++i) jie[i]=(ll)jie[i-1]*i%mod;
        inv[n]=qm(jie[n],mod-2);
        for(reg i=n-1;i>=0;--i){
            inv[i]=(ll)inv[i+1]*(i+1)%mod;
        }
        ll ans=0;
        for(reg i=1;i<=n;++i){
            for(reg j=0;j<=i;++j){
                if(j&1) ans=mo(ans+mod-(ll)C(i,j)*f[0][i-j]%mod);
                else ans=mo(ans+(ll)C(i,j)*f[0][i-j]%mod);
            }
        }
        printf("%lld",ans);
        return 0;
    }
    
    }
    signed main(){
    //    freopen("4.in","r",stdin);
    //    freopen("4.out","w",stdout);
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/2/9 21:08:53
    */

    总结:

    建出树形结构

    考虑链的拼凑情况。——O(n^3)

    神仙二项式反演——O(n^2)

    二项式反演这里,利用“前i个编号分配”其实是容易考虑的。因为不用“恰好”,所以不用枚举具体用哪几个

    把   恰好->前i个 然后容斥(二项式反演本身就是容斥(也可以大力推式子))

    我们实际上把“恰好”放在了外面,最后二项式反演时候再考虑。

  • 相关阅读:
    Java——static
    Java——package与import
    Java——方法重写
    Java——super
    Java——类的继承、访问控制
    Java——API文档
    Java——对象转型
    Java——动态绑定和多态
    Java——抽象类
    redis在linux上的安装和配置
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10358492.html
Copyright © 2011-2022 走看看