原题链接:Arc106 D Powers
题目大意:给定正整数(n,k)以及一数列({a})长度为(n)。对于所有正整数(xin[1,k])求如下表达式$$sumlimits_{1leq l < rleq n}(a_l + a_r) ^ x$$
数据范围:
(1 leq n leq 2*10^5)
(1 leq k leq 300)
(1 leq a_i leq 10^8)
思路:不难观察到(n)的范围非常自然的提高到了(2*10^5),但是(k)的范围特别小,(O(nk))是可以承受的复杂度,先可以提取到这个大概的复杂度的信息。其次可以通过式子想到二项式定理进行拆分,对于某个指定的(x),原式等价$$sumlimits_{1leq l < r leq n}sumlimits_{i=0}^x inom{x}{i}a_l^i a_r^{x-i}$$然而遗憾的是这个式子的形式还是非常复杂,由于(1 leq l < r leq n)这个非常丑的式子的存在,导致求和这件事情很难快速得到,但是想当然地,如果这里的限制条件是不存在的,范围是(1 leq l,r leq n)那么求和的表达式可以通过调换求和的顺序变成$$sumlimits_{i=0}xinom{x}{i}sumlimits_{l=1}n a_lisumlimits_{r=1}n a_r^{x-i}$$而式子的后半节是可以通过预处理在(O(nk))的代价下得到的,而系数部分可以通过乘法逆元以(O(N))的代价预处理。两边查询的代价都是(O(1))的。那么只要事情能走到这样对所有元素的求和,就可以化简到一个可以接受的式子。考虑如何拼出整个的求和:如果把原来式子的(l,r)调换得到的式子与原来的式子想加,那么得到的式子就是$$sumlimits_{1leq l,rleq n,l eq r}sumlimits_{i=0}xinom{x}{i}a_lia_r{x-i}$$那么,只需要把整个的部分里挖掉$l=r$的情况,也就是$$sumlimits_{j=1}nsumlimits_{i=0}xa_jia_j{x-i}inom{x}{i}$$接着可以发现后半部分很好合并,调换求和顺序之后得到$sumlimits_{j=1}^na_j^xsumlimits_{i=0}^ninom{x}{i}$根据二项式求和,可以进一步的得到$sumlimits_{j=1}^n(2a_j)^x$。于是可得,两个式子加起来的结果就是$$sumlimits_{i=0}xinom{x}{i}sumlimits_{l=1}na_lisumlimits_{r=1}n{a_r{x-i}}-sumlimits_{j=1}n(2a_j)x$$。回到之前的一步,将(l,r)调换,由于(inom{n}{i} == inom{x}{x-i})于是可以得到两个式子是相等的,即答案=上面的式子的一半。当然,这里题目要求取模,于是要乘乘法逆元。最后分别预处理,最后以(O(k^2))的代价计算所有结果即可。
代码:
#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
const int N = 2e5+7,M = 305,MOD = 998244353;
ll fx[M],fc[M],fsa[M],fsb[M];
int a[N],b[N];
ll fa[N][M],fb[N][M];
ll qmul(ll a, ll b, ll P)
{
ll L = a * (b >> 25LL) % P * (1LL << 25) % P;
ll R = a * (b & ((1LL << 25) - 1)) % P;
return (L + R) % P;
}
ll qpow(ll a,ll b,ll p)
{
ll res = 1 % p;
while(b)
{
if(b & 1) res = res * a % p;
a = a * a % p;
b >>= 1;
}
return res;
}
ll fact[N],infact[N];
void init()
{
fact[0] = infact[0] = 1;
for (int i = 1; i < N; i ++ )
{
fact[i] = ((ll)fact[i - 1] * i) % MOD;
infact[i] = ((ll)infact[i - 1] * qpow(i, MOD - 2, MOD)) % MOD;
}
}
ll C(int a,int b)
{
return (ll)fact[a]*infact[b]%MOD*infact[a-b]%MOD;
}
int main()
{
init();
int n,k,rev2 = qpow(2,MOD - 2,MOD);scanf("%d%d",&n,&k);
forn(i,1,n) scanf("%d",&a[i]),b[i] = 2 * a[i];
fsa[0] = n,fsb[0] = n;
forn(i,1,n)
{
ll _a = 1,_b = 1;
forn(j,1,k)
{
_a = _a * a[i] % MOD,_b = _b * b[i] % MOD;
fsa[j] = (fsa[j] + _a) % MOD,fsb[j] = (fsb[j] + _b) % MOD;
}
}
forn(x,1,k)
{
ll lf = 0;
forn(i,0,x)
{
ll t = fsa[i] * fsa[x - i] % MOD;
t = t * C(x,i) % MOD;
lf = (lf + t) % MOD;
}
// cout << lf << endl;
lf = ((lf - fsb[x]) % MOD + MOD) % MOD;
printf("%lld
",rev2 * lf % MOD);
}
return 0;
}