https://www.acmicpc.net/problem/28212
\(1\) 이상 \(n\) 이하의 자연수 \(k\)개로 이루어진 임의의 쌍 \((a_1, ..., a_k)\)에 대하여 함수 \(y=|x-a_1|+...+|x-a_k|\)가 최소가 되는 \(x\)의 값들 중 최솟값을 모든 가능한 \((a_1, ..., a_k)\) 쌍에 대하여 구한 후 그 합을 \(998244353\)으로 나눈 나머지를 출력하는 문제입니다. 시간 제한은 \(2\)초, 메모리 제한은 \(1024\)MB입니다.
함수 \(y=|x-a_1|+...+|x-a_k|\)가 최소가 되는 \(x\)의 값들 중 최솟값이 \(i\)라는 것은, \(a_1, ..., a_k\)을 오름차순으로 정렬했을 때 \(1\) 이상 \(i-1\) 이하의 자연수의 개수가 \(\lfloor \frac{k+1}{2} \rfloor\)개 미만이고, \(1\) 이상 \(i\) 이하의 자연수의 개수가 최초로 \(\lfloor \frac{k+1}{2} \rfloor\)개 이상이 되었다는 것입니다.
다르게 말하면, 함수 \(y=|x-a_1|+...+|x-a_k|\)가 최소가 되는 \(x\)의 값들 중 최솟값이 \(i\) 이상이라는 것은, \(a_1, ..., a_k\)을 오름차순으로 정렬했을 때 \(1\) 이상 \(i-1\) 이하의 자연수의 개수가 \(\lfloor \frac{k+1}{2} \rfloor\)개 미만이라는 것입니다.
함수 \(y=|x-a_1|+...+|x-a_k|\)가 최소가 되는 \(x\)의 값들 중 최솟값이 \(i\)인 \((a_1, ..., a_k)\) 쌍의 개수를 \(N(X=i)\), 최솟값이 \(i\) 이상인 \((a_1, ..., a_k)\) 쌍의 개수를 \(N(X\geq i)\)로 표기합시다. 그러면 문제의 답은 다음과 같습니다. \[\sum_{i=1}^{n}iN(X=i)=\sum_{i=1}^{n}N(X\geq i) \mod 998244353\]
\(N(X\geq i)\)는 \(1, ..., i-1\) 중에서 중복을 허용하여 \(j\)개를 뽑고 (단, \(0 \leq j \leq \lfloor \frac{k+1}{2} \rfloor-1\)), \(i, ..., n\) 중에서 중복을 허용하여 \(k-j\)개를 뽑은 후, 이들로 \((a_1, ..., a_k)\)를 구성하는 경우의 수를 모두 더하여 구할 수 있습니다. 단, 이때 \(0^0=1\)으로 생각합니다. \[N(X \geq i)=\sum_{j=0}^{\lfloor \frac{k-1}{2} \rfloor}\binom{k}{j}(i-1)^j(n-i+1)^{k-j}\]
이를 종합하면 답은 다음과 같습니다. \begin{align}& \sum_{i=1}^{n}\sum_{j=0}^{\lfloor \frac{k-1}{2} \rfloor}\binom{k}{j}(i-1)^j(n-i+1)^{k-j} \\ &= n^k + \sum_{i=1}^{n-1}\sum_{j=0}^{\lfloor \frac{k-1}{2} \rfloor}\binom{k}{j}i^j(n-i)^{k-j} \\ &= n^k + \frac{1}{2}\sum_{i=1}^{n-1}\sum_{j=0}^{\lfloor \frac{k-1}{2} \rfloor}[\binom{k}{j}i^j(n-i)^{k-j} + \binom{k}{k-j}i^{k-j}(n-i)^j] \\ &= \begin{cases} n^k + \frac{1}{2}\sum_{i=1}^{n-1}\sum_{j=0}^{k}\binom{k}{j}i^j(n-i)^{k-j} & \text{ if } k \text{ is odd} \\ n^k + \frac{1}{2}\sum_{i=1}^{n-1}[(\sum_{j=0}^{k}\binom{k}{j}i^j(n-i)^{k-j})-\binom{k}{k/2}i^{k/2}(n-i)^{k/2}] & \text{ if } k \text{ is even} \end{cases} \\ &= \begin{cases} n^k + \frac{1}{2}(n-1)n^k & \text{ if } k \text{ is odd} \\ n^k + \frac{1}{2}\sum_{i=1}^{n-1}[n^k-\binom{k}{k/2}i^{k/2}(n-i)^{k/2}] & \text{ if } k \text{ is even} \end{cases} \\ &= \frac{1}{2}(n+1)n^k - \begin{cases} 0 & \text{ if } k \text{ is odd} \\ \frac{1}{2}\binom{k}{k/2}\sum_{i=1}^{n-1}i^{k/2}(n-i)^{k/2} & \text{ if } k \text{ is even} \end{cases} \mod 998244353 \end{align}
시간복잡도는 \(O(n\lg k)\) 입니다.
코드는 다음과 같습니다.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mod 998244353
ll f[1000010], invf[1000010];
ll power(ll a, ll b)
{
ll ret=1;
while(b)
{
if(b&1) ret=ret*a%mod;
a=a*a%mod;
b>>=1;
}
return ret;
}
ll inv(ll a)
{
return power(a, mod-2);
}
ll binom(ll n, ll k)
{
return f[n]*invf[k]%mod*invf[n-k]%mod;
}
int main()
{
f[0]=1;
for(ll i=1;i<=1000000;i++) f[i]=f[i-1]*i%mod;
invf[1000000]=power(f[1000000], mod-2);
for(ll i=1000000-1;i>=0;i--) invf[i]=invf[i+1]*(i+1)%mod;
assert(invf[0]==1);
ll n, k;
cin>>n>>k;
ll ans=(n+1)*power(n, k)%mod*inv(2)%mod;
if(k&1) cout<<ans;
else
{
ll tmp=0;
for(ll i=1;i<=n-1;i++)
{
tmp=(tmp+power(i*(n-i)%mod, k/2))%mod;
}
tmp=tmp*binom(k, k/2)%mod*inv(2)%mod;
cout<<(ans-tmp+mod)%mod;
}
}

'Programming > Algorithm' 카테고리의 다른 글
| [Algorithm] BOJ 17372. 피보나치 수의 최대공약수의 합 (0) | 2024.09.06 |
|---|---|
| [Algorithm] KMP (1) | 2024.01.04 |
| [Algorithm] Manacher's Algorithm (0) | 2024.01.03 |