题号是洛谷题号。
前置知识:\(\sum_{i=1}^{n}a_i=m\),\(\{a_n\in N^*\}\) 方案数为 \(C_{n+m-1}^{n-1}\),\(\sum_{i=1}^{n}a_i\ge m\) 方案数为 \(C_{n+m}^{n}\),后一项的证明就是考虑有 \(n\) 个隔板和 \(m\) 个物体隔板,然后隔出来有 \(n+1\) 个物品,最后一项物品舍弃掉即可。
设 \(\{a_n\}\) 降序排列后为 \(\{b_n\}\),要统计 \(b_m=b_{m+1}\) 不好统计,因为你不知道 \(b_m\) 有多少个,但是可以统计 \(b_m>b_{m+1}\) 即非法序列个数。
首先将 \(\sum a_i\in[L,R]\) 弱化成 \(\sum a_i\le R\),就是差分一下 Solve(R)-Solve(L-1)
。
枚举 \(b_m\) 的值 \(x\),设 \(f(s,x,y)\) 表示当前序列总和小于等于 \(s\),\(m\) 个数大于等于 \(x\),剩余 \(n-m\) 个数小于 \(x\) 的方案数,那么 \(b_m=x\) 时这一块的非法序列个数就是 \(f(s,x,x)-f(s,x+1,x)\)。
考虑如何求 \(f(s,x,y)\),先选 \(m\) 个位置作为 \(\ge x\) 的位置,剩余 \(n-m\) 位置小于 \(y\),但是注意到隔板法不好求对每个数上界和下界(非 0)有限制的方案数,于是考虑容斥,枚举 \(i\in [0,n-m]\) 表示 \(n-m\) 个位置中至少有 \(i\) 个位置 \(>=y\),将这 \(i\) 个位置和之前的 \(\ge x\) 的数全部从和当中减掉,新和就是 \(s-mx-iy\),然后又要求减掉后的序列和小于等于 \(s-mx-iy\),于是有:
\[f(s,x,y)=C_n^m\sum_{i=0}^{n-m}(-1)^iC_{n-m}^{i}C_{s-mx-iy+n}^n \]因此最后非法序列个数就是 \(\sum_{x=1}^{m}f(s,x,x)-f(s,x+1,x)\),总序列个数 \(C_{n+s}^{n}\) 减去即可。
由于要求 \(s-mx-iy\ge0\),而 \(iy\) 成倍数增长,所以实际复杂度为调和级数。
Code:
/*
========= Plozia =========
Author:Plozia
Problem:AT5169 Candy Retribution
Date:2022/9/25
========= Plozia =========
*/
#include <bits/stdc++.h>
#define int long long
typedef long long LL;
const int MAXN = 6e5 + 5;
const LL P = 1e9 + 7;
int n, m, l, r;
LL fact[MAXN], inv[MAXN];
int Read()
{
int sum = 0, fh = 1; char ch = getchar();
for (; ch < '0' || ch > '9'; ch = getchar()) fh -= (ch == '-') << 1;
for (; ch >= '0' && ch <= '9'; ch = getchar()) sum = (sum << 3) + (sum << 1) + (ch ^ 48);
return sum * fh;
}
LL ksm(LL a, LL b = P - 2, LL p = P)
{
LL s = 1 % p;
for (; b; b >>= 1, a = a * a % p)
if (b & 1) s = s * a % p;
return s;
}
LL C(LL n, LL m) { return fact[n] * inv[m] % P * inv[n - m] % P; }
LL f(int x, int y, int s)
{
LL sum = 0;
for (int i = 0; i <= n - m; ++i)
{
if (1ll * s - m * x - i * y < 0) return sum * C(n, m) % P;
sum = (sum + ((i & 1) ? -1 : 1) * C(n - m, i) * C(1ll * s - m * x - i * y + n, n) % P) % P;
sum = (sum + P) % P;
}
return sum * C(n, m) % P;
}
LL Solve(int s)
{
LL sum = 0;
for (int i = 1; i <= s; ++i)
sum = ((sum + f(i, i, s) - f(i + 1, i, s)) % P + P) % P;
return (C(s + n, n) % P - sum + P) % P;
}
signed main()
{
n = Read(), m = Read(), l = Read(), r = Read();
fact[0] = 1; for (int i = 1; i <= 600000; ++i) fact[i] = fact[i - 1] * i % P;
inv[600000] = ksm(fact[600000]); for (int i = 599999; i >= 0; --i) inv[i] = (i + 1) * inv[i + 1] % P;
printf("%lld\n", ((Solve(r) - Solve(l - 1)) % P + P) % P); return 0;
}
标签:AT5169,Retribution,ch,inv,int,sum,Candy,iy,LL
From: https://www.cnblogs.com/Plozia/p/16731510.html