Автор проблеми: | De3b0o |
Підготовлено: | De3b0o |
Редагував: | Hasan Saleh (MathModel) |
Рішення
Спочатку давайте підрахуємо всі можливі масиви, ігноруючи останню умову.
Проблема зводиться до:
\textbf{Підрахуйте кількість масивів розміру } m \le x \textbf{, сума яких дорівнює } n.
Це стандартна задача \textbf{зірки та бари}, відповідь для фіксованого :
Отже, загальна кількість масивів (ігноруючи останню умову) дорівнює:
Ми назвемо цю кількість Загальна.
Тепер ми повинні виключити масиви, де \max - \min < k, ми назвемо їх ПЛОХІ масиви.
Якщо \max - \min < k, тоді всі елементи масиву лежать у деякому інтервалі довжини не більше k-1. Тобто, існує деяке ціле число , таке що:
Зафіксуємо (розмір масиву), (мінімальний елемент у масиві) та (кількість елементів у масиві, які дорівнюють ).
Ми можемо побачити, що кількість ПЛОХИХ масивів з фіксованими , та дорівнює:
Де f(x,y) — це кількість масивів розміру та суми , такі що всі елементи знаходяться в діапазоні [1,k-1].
Ми можемо обчислити \displaystyle \binom{m}{c} за , використовуючи деякі попередні обчислення.
І ми можемо обчислити всі можливі f(x,y), використовуючи динамічне програмування:
Перехід:
Ми використовуємо префіксні суми, щоб кожен стан можна було обчислити за .
Загальна складність динамічного програмування дорівнює \mathcal{O}(n \cdot x), оскільки \max i = n , \max j = x.
Тепер відповідь повинна бути Загальна мінус кількість ПЛОХИХ масивів.
Іншими словами:
Для кожного (1 \le m \le x) існує \frac{n}{m} різних значень , і різних значень , тому складність дорівнює \displaystyle \mathcal{O}(\sum_{m=1}^x \frac{n}{m} \cdot m) = \mathcal{O}(n \cdot x).
Отже, загальна складність коду дорівнює \mathcal{O}(n \cdot x), що достатньо швидко, щоб пройти.
Наступне — реалізація:
#include<bits/stdc++.h>
#define ll long long
#define F first
#define S second
#define in insert
#define pb push_back
#define d3 ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define cans cout << ans << "\n";
#define yes cout << "YES" << "\n";
#define no cout << "NO" << "\n";
#define pll pair<ll,ll>
#define lin cout << "\n";
#define mid ((l+r)/2)
#define lc (2*x)
#define rc (2*x+1)
#define double long double
using namespace std;
mt19937 rnd(time(0));
const ll N = 1e5+9 , m = 1e9+7;
ll n , x , k;
int dp[N][501] , p[N];
ll ans = 0;
ll f[N] , inv[N];
ll fp(ll x , ll y)
{
if(y==0)
return 1;
ll z = fp(x,y/2);
z*=z;
z%=m;
if(y&1)
return z*x%m;
else
return z;
}
ll c(ll x , ll y)
{
if(y>x||y<0||x<0)
return 0;
return f[x]*inv[y]%m*inv[x-y]%m;
}
int main()
{
d3
cin >> n >> x >> k;
f[0]=1;
for(ll i = 1 ; N>i ; i++)
f[i]=f[i-1]*i%m;
for(ll i = 0 ; N>i ; i++)
inv[i]=fp(f[i],m-2);
for(int sz = 1 ; x>=sz ; sz++)
{
ans+=c(n-1,sz-1);
if(ans>m)
ans-=m;
}
if(k==0)
{
cout << ans;
return 0;
}
ans--;
dp[0][0]=1;
for(int sz = 1 ; x>=sz ; sz++)
{
p[0]=dp[0][sz-1];
for(int i = 1 ; n>=i ; i++)
{
p[i]=p[i-1]+dp[i][sz-1];
if(p[i]>m)
p[i]-=m;
}
for(int sum = 1 ; n>=sum ; sum++)
{
dp[sum][sz]=p[sum-1];
if(sum>=k)
dp[sum][sz]-=p[sum-k];
if(dp[sum][sz]<0)
dp[sum][sz]+=m;
}
}
for(int sz = 2 ; x>=sz ; sz++)
{
for(int j = 1 ; sz>=j ; j++)
{
ll e = 0;
for(int i = n-sz ; i>=0 ; i-=sz)
e+=dp[i][sz-j];
e%=m;
e*=c(sz,j);
e%=m;
ans-=e;
if(ans<0)
ans+=m;
}
}
cout << ans;
}