zoukankan      html  css  js  c++  java
  • HDOJ 4903 The only survival

    Discription:
    There is an old country and the king fell in love with a devil. The devil always ask the king to do some crazy things. Although the king used to be wise and beloved by his people. Now he is just like a boy in love and can’t refuse any request from the devil. Also, this devil is looking like a very cute Loli. 

    Something bad actually happen. The devil makes this kingdom's people infected by a disease called lolicon. Lolicon will take away people's life in silence. 

    Although z*p is died, his friend, y*wan is not a lolicon. Y*wan is the only one in the country who is immune of lolicon, because he like the adult one so much. 

    As this country is going to hell, y*wan want to save this country from lolicon, so he starts his journey. 

    You heard about it and want to help y*wan, but y*wan questioned your IQ, and give you a question, so you should solve it to prove your IQ is high enough. 

    The problem is about counting. How many undirected graphs satisfied the following constraints? 

    1. This graph is a complete graph of size n. 
    2. Every edge has integer cost from 1 to L. 
    3. The cost of the shortest path from 1 to n is k. 

    Can you solve it? 

    output the answer modulo 10^9+7 

    Input

    The first line contains an integer T, denoting the number of the test cases. 

    For each test case, the first line contains 3 integers n,k,L

    T<=5 n,k<=12,L<=10^9.

    Output

    For each test case, output the answer in one line.

    Sample Input

    2
    3 3 3
    4 4 4

    Sample Output

    8
    668

    陈立杰大神出的题,想了想又写了写2h就过去了orz
    题目大意就是给出n,k,L ,问有多少n个点的带标号的完全无向图,
    满足1-n的最短路长度为k,且每条边的权值都>=1且<=L 。

    (要不是上午ZHW点拨了几下我估计一晚上都做不出来hhh)

    首先不能枚举最短路的构成,这样显然会挂掉,因为1-n可能会有很多条最短的路径;

    然后考虑一下枚举每一个dis[i],代表1号节点到i号节点的最短路长度。
    假设我们不用管枚举dis的时间花费,先关注一下如果dis都确定了的话如何更新答案。
    先把dis从小到大排序,之后从后面的点向前面的每个节点连边(这样才能是完全图嘛。。)。
    边权显然不是任意的,可以发现的是如果1到i(代表最短路长度从小到大排序后第i小点)
    的最短路长度为dis[i]的话,必须满足:
    1.对于所有的dis[j]<dis[i],
    使得dis[j]+val(j,i)>=dis[i]
    2.存在dis[j]<dis[i],
    使得dis[j]+val(j,i)==dis[i]
    满足上两个条件的方案数不难求,一个容斥就ojbk了。
    然后再考虑dis[j]==dis[i]的点j,发现边权是多少都无所谓,所以都×L就行了。

    但是可能会有点的dis>k,这可怎么办呢?
    这样就设dis[i]==k(这里i!=n)的意思为1到i的最短路长度>=k,
    那么我们统计这类节点的方案数就不用容斥减去了,直接乘上满足条件1的方案数就行了。

    但是搜索出每个dis[i]的值是会TLE的,需要考虑一种更加高效的方法。

    其实我们不必知道每个dis是多少,只需要知道对于1<=x<=k的每个x,dis[i]==x的i有多少个就行了。
    这样我们改变搜索对象(实验证明这样搜索能到达的状态最多有10^5种,再乘上n^2的更新答案时间根本不虚),
    中间计算的时候乘上组合数就行了(相当于算等于x的dis[i]分别对应原图中的哪些节点)

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<algorithm>
    #include<map>
    #include<cstring>
    #define ll long long
    #define ha 1000000007
    using namespace std;
    ll n,k,L,T,ans;
    ll C[105][105],jc[105];
    ll num[105],cnt=0;
    ll ci[105][105];
    
    inline void init(){
        C[0][0]=jc[0]=1;
        for(int i=1;i<=30;i++){
            C[i][0]=1,jc[i]=jc[i-1]*(ll)i%ha;
            for(int j=1;j<=i;j++){
                C[i][j]=C[i-1][j-1]+C[i-1][j];
                if(C[i][j]>=ha) C[i][j]-=ha;
            }
        }
    }
    
    inline ll calc(){
        ll an=1,rk1,rk2,fin=num[k];
        num[k]=1;
        //先算num<k和num==k中的n的情况。
        for(int i=1;i<=k;i++) if(num[i]){
            rk1=rk2=1;
            for(int j=0;j<i;j++) if(num[j]){
                rk1=rk1*ci[i-j-1][num[j]];
                rk2=rk2*ci[i-j][num[j]];
                if(rk1>=ha) rk1-=rk1/ha*ha;
                if(rk2>=ha) rk2-=rk2/ha*ha;
            }
            
            rk1+=ha-rk2;
            if(rk1>=ha) rk1-=ha;
            
            for(int j=1;j<=num[i];j++){
                an=an*rk1;
                rk1=rk1*L;
                if(an>=ha) an-=an/ha*ha;
                if(rk1>=ha) rk1-=rk1/ha*ha;
            }
        }
        
        //再求num==k的其他点的方案数
        num[k]=fin-1;
        if(num[k]){
            rk1=1;
            for(int i=0;i<k;i++) if(num[i]){
                rk1=rk1*ci[k-i-1][num[i]];
                if(rk1>=ha) rk1-=rk1/ha*ha;            
            }
            
            for(int j=1;j<=num[k];j++){
                rk1=rk1*L;
                if(rk1>=ha) rk1-=rk1/ha*ha;
                an=an*rk1;
                if(an>=ha) an-=an/ha*ha;
            }
        }
        
        return an;
    }
    
    void dfs(int tmp,int lef,ll alr){
        if(tmp==k-1){
            num[k]=lef+1;
            ans+=alr*calc()%ha;
            if(ans>=ha) ans-=ha;
            return;
        }
        
        for(int u=0;u<=lef;u++){
            ll to=alr*C[lef][u]%ha;
            num[tmp+1]=u;
            dfs(tmp+1,lef-u,to);
        }
    }
    
    inline void solve(){
        dfs(0,n,1);
    }
    
    int main(){
        init();
        scanf("%lld",&T);
        while(T--){
            ans=0; memset(num,0,sizeof(num));
            memset(ci,0,sizeof(ci));
            
            scanf("%lld%lld%lld",&n,&k,&L);
            if(L<k){
                puts("0");
                continue;
            }
            
            for(int i=0;i<=k;i++){
                ci[i][0]=1;
                for(int j=1;j<=n;j++) ci[i][j]=ci[i][j-1]*(L-i+ha)%ha;
            }
                    
            n-=2,num[0]=num[k]=1,solve();
            printf("%lld
    ",ans);
        }
        
        return 0;
    }
    
    
    




  • 相关阅读:
    CSS
    Form表单
    HTML入门(HB、DW)
    第一次接触HBuild
    python 数据结构中被忽视的小技巧
    flask扩展模块flask-sqlachemy 的使用---mysql数据库
    flask蓝图的使用
    基于爬虫的天气预报程序
    一个爬取股票信息的爬虫程序
    向python3进发
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8298635.html
Copyright © 2011-2022 走看看