HDU - 6409:没有兄弟的舞会(数学+思维)

链接:HDU - 6409:没有兄弟的舞会

题意:

题解:

求出最大的 l[i] 的最大值 L 和 r[i] 的最大值 R,那么 h 一定在 [L, R] 中。枚举每一个最大值,那么每一个区间的对于答案的贡献就是一个等差数列的和(乘法分配律),将每一个和乘起来就是该最大值的对于答案的贡献。但是相同最大值可能来自于多个区间,如果枚举每一个可能出现最大值的区间,那么会超时,所以需要一个神奇的方法,我也不知道原理是什么,但是数学上就是直接的式子,可以分解出来。

#include <bits/stdc++.h>
using namespace std;

const double EPS = 1e-6;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 1e4 + 10;
int n;
int l[maxn], r[maxn];

void Exgcd(long long a, long long b, long long& x, long long& y)
{
    if(!b){
        y = 0; x = 1;
        return ;
    }
    Exgcd(b, a % b, y, x);
    y -= a / b * x;
}

long long NY(long long a, long long b)
{
    long long x, y;
    Exgcd(a, b, x, y);
    return (x % mod + mod) % mod;
}

long long Inv(int l[], int r[], int n)
{
    long long ans = 1;
    for(int i = 0; i < n; i++){
        ans = ans * (r[i] - l[i] + 1) % mod;
    }
    return NY(ans, mod);
}


int main()
{

    int T;
    scanf("%d", &T);
    while(T--){
        scanf("%d", &n);
        int L = 0, R = 0;
        for(int i = 0; i < n; i++){
            scanf("%d%d", &l[i], &r[i]);
            L = max(L, l[i]);
            R = max(R, r[i]);
        }

        long long ans = 0;
        for(int h = L; h <= R; h++){
            long long cnt = 1, num = 1;
            for(int i = 0; i < n; i++){
                long long x = h - l[i] + 1, y = max(0, h - r[i]) + 1;
                long long sum = (x + y) * (x - y + 1) / 2;
                cnt = cnt * sum % mod;

                if(r[i] >= h) num = num * (sum - 1) % mod;
                else num = num * sum % mod;
            }
            ans = ((ans + cnt - num) % mod + mod) % mod;
        }

        ans = ans * Inv(l, r, n) % mod;

        printf("%lld\n", ans);
    }
    return 0;
}

 

posted @ 2018-08-21 11:23  鬼沐冢  阅读(344)  评论(0编辑  收藏  举报