• Hdu4903 The only survival


    The only survival

    Time Limit: 40000/20000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
    Total Submission(s): 255    Accepted Submission(s): 120

    Problem Description
    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
    Author
    WJMZBMR
    Source
    题目大意:有一张n个点的无向完全图,第i个点的编号是i,每条边的边权在1到L之间的正整数,问存在多少个图使得1到n的最短路是k。
    分析:神题!
       一个暴力的做法是枚举所有点到1号点的最短路,记作d[i],如果d[i] == d[j],那么i,j之间的边的权值可以任意选,否则边权不能小于|di-dj|,且必然有一条边使得di + dist[i][j] = dj.只是枚举的复杂度高达13^12,承受不了.
       其实我们不需要考虑每个点的最短路具体是什么,只需要考虑数量就可以了.计数题的一个转换思路.那么在dfs的时候枚举每个最短路对应的点有多少个就可以了.然后就是极其琐碎的组合数运算.
       需要注意的是起点和终点的最短路都已经确定了.选取i个点的组合数要排除这两个点. 同时可能会有大于k的最短路出现,统统放到k+1处理.关于具体的组合数的运算我写在了代码里:
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    const int mod = 1e9+7;
    int T;
    ll n,k,l,cnt[20],ans,c[25][25];
    
    void init()
    {
        c[0][0] = 1;
        for (int i = 1; i <= 20; i++)
        {
            c[i][0] = 1;
            for (int j = 1; j <= 20; j++)
                c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
        }
    }
    
    ll qpow(ll a,ll b)
    {
        ll res = 1;
        while (b)
        {
            if (b & 1)
                res = (res * a) % mod;
            a = (a * a) % mod;
            b >>= 1;
        }
        return res;
    }
    
    ll solve(ll x)
    {
        if (!cnt[x])
            return 1;
        ll x1 = 1,x2 = 1;
        for (int i = 0; i < x; i++)
        {
            if (!cnt[i])
                continue;
            if (x - i > l)  //方案不合法,最短路会被更新
                return 0;
            x1 = (x1 * qpow(l - (x - i) + 1,cnt[i])) % mod;   //x1是所有能选的方案
            x2 = (x2 * qpow(l - (x - i),cnt[i])) % mod;  //x2是所有不合法的方案
        }
        if (x == k + 1)   //如果最短路大于k了,那么所有能选的方案都是合法的,因为只是把它们归到k+1这一类,最短路并不一定要等于k+1
            return qpow(x1,cnt[x]) % mod;
        x1 -= x2;
        if (x1 < 0)
            x1 += mod;
        return qpow(x1,cnt[x]) % mod;   //之前的方案数都是对于所有的i,1个x来计算的.
    }
    
    void dfs(ll dep,ll fangan,ll tot)  //tot传的是1
    {
        if (dep == k)
        {
            for (int i = 1; i + tot <= n; i++)
            {
                ll temp = fangan * c[n - tot - 1][i - 1] % mod;   //剩下的点中选i-1个最短路为k的点,第i个点为终点,不考虑.
                temp = (temp * qpow(l,c[i][2])) % mod;   //这两行就是两两最短路相等的算方案数
                temp = (temp * qpow(l,c[n - tot - i][2])) % mod;
                cnt[k] = i;
                cnt[k + 1] = n - tot - i;
                temp = (temp * solve(k)) % mod;
                temp = (temp * solve(k + 1)) % mod;  //最短路大于k的都放到k+1处计算.
                ans = (ans + temp) % mod;
            }
            return;
        }
        for (int i = 0; i + tot < n; i++)
        {
            cnt[dep] = i;
            ll temp = fangan * qpow(l,c[i][2]) % mod;   //上面说的di == dj的情况,边权随便取
            temp = (temp * c[n - tot - 1][i]) % mod;   //能选的点中选i个点的方案数
            temp = (temp * solve(dep)) % mod;
            dfs(dep + 1,temp,i + tot);
        }
    }
    
    int main()
    {
        scanf("%d",&T);
        init();
        while (T--)
        {
            scanf("%lld%lld%lld",&n,&k,&l);
            memset(cnt,0,sizeof(cnt));
            cnt[0] = 1;  //起点被确定了
            ans = 0;
            dfs(1,1,1);
            printf("%lld
    ",ans);
        }
    
        return 0;
    }
  • 相关阅读:
    (八十五)c#Winform自定义控件-引用区块-HZHControls
    (八十四)c#Winform自定义控件-导航菜单(Ribbon菜单)-HZHControls
    (八十三)c#Winform自定义控件-导航菜单(扩展)-HZHControls
    (八十二)c#Winform自定义控件-穿梭框-HZHControls
    (八十一)c#Winform自定义控件-时间轴-HZHControls
    (八十)c#Winform自定义控件-分割线标签-HZHControls
    (七十九)c#Winform自定义控件-导航菜单-HZHControls
    (七十八)c#Winform自定义控件-倒影组件-HZHControls
    (七十七)c#Winform自定义控件-采样控件-HZHControls
    (七十六)c#Winform自定义控件-表单验证组件-HZHControls
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8448654.html
Copyright © 2020-2023  润新知