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

时间:2023-03-09 08:17:41
HDU - 6409:没有兄弟的舞会(数学+思维)

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

题意:

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

题解:

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

#include <bits/stdc++.h>
using namespace std; const double EPS = 1e-;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
const int maxn = 1e4 + ;
int n;
int l[maxn], r[maxn]; void Exgcd(long long a, long long b, long long& x, long long& y)
{
if(!b){
y = ; x = ;
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 = ;
for(int i = ; i < n; i++){
ans = ans * (r[i] - l[i] + ) % mod;
}
return NY(ans, mod);
} int main()
{ int T;
scanf("%d", &T);
while(T--){
scanf("%d", &n);
int L = , R = ;
for(int i = ; i < n; i++){
scanf("%d%d", &l[i], &r[i]);
L = max(L, l[i]);
R = max(R, r[i]);
} long long ans = ;
for(int h = L; h <= R; h++){
long long cnt = , num = ;
for(int i = ; i < n; i++){
long long x = h - l[i] + , y = max(, h - r[i]) + ;
long long sum = (x + y) * (x - y + ) / ;
cnt = cnt * sum % mod; if(r[i] >= h) num = num * (sum - ) % 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 ;
}