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; }