ARC 106 D题解
竟然有蒟蒻会做的 ARC D,泪目。
题目简述:
对于每一个 \(x\leq k\),求:
不保证没有其他神仙一万倍的算法。
这个,关于这种相加求幂的形式,我好像只会二项式定理。
对于我来说能想到变换求和顺序就很不错了,果真我后面就暂时性卡住了。
开始想到这些东西互相影响,好像变换求和顺序之后并没有什么好处。
那能不能让他不影响?
我直接玩后面哪两个求和,为了方便,先让指数都是 \(1\)。
那么这个东西是 \(a_1a_2+a_1a_3+a_2a_3\) 。
比较难做,但是,
我们知道这种形式是比较好做的:
其实他们差的只是 \(a_i^2\) 和另一个他自己。
考虑加上指数?进一步可以得到:
然后这个单求是很不可做的,但是,考虑到:
\(i\) 的枚举范围是 \(0\sim x\),我们不仅要枚举 \((i,x-i)\) 的系数组合,还要枚举 \((x-i,i)\) 的系数组合。
更重要的是:
对上面那个东西移项容易得到:
在系数相同的前提下,这个东西完全可以合并起来一起算。
我们发现当 \(2 \nmid x\) 时,正好可以合并 \(\dfrac{x-1}{2}\) 对,那么容易发现最后的答案是:
我们发现后面这个预处理一下,时间复杂度是 \(\mathcal O(nk)\) 的,对于组合数我们先把阶乘搞出来,每次求就是 \(\mathcal O(\log p)\) 了,总的时间复杂度容易分析为 \(\mathcal O(k^2\log p+nk)\),对于 ATCoder 的神仙机器和这么大的时空限制(好像和 ATCoder 标准时空差不多......),完全可以过了。
嗯,你又问 \(2 \mid x\) 怎么做。
首先对于除了中间那个 \(\dfrac{x}{2}\) 和上面的算法是一样的。
我们将 \(\dfrac{x}{2}\) 暴力带入上面那个式子可以发现:
然后容易解出:
我们手算就能得到 \(2\) 在 \(\bmod 998244353\) 意义下的逆元是 \(499122177\)。
总结一下:
下面是参考代码:
#include"iostream"
#include"cstdio"
#include"cmath"
#include"cstring"
#include"algorithm"
#include"stack"
#include"queue"
using namespace std;
#define read(x) scanf("%d",&x)
#define readl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define MOD 998244353
#define MAXN 200005
int n,k;
ll sum[305],Cs[305];
ll fac[305];
ll a[MAXN];
ll quickpow(ll a,ll b)
{
ll ans=1,base=a;
while(b)
{
if(b&1) ans=ans*base%MOD;
b>>=1;
base=base*base%MOD;
}
return ans%MOD;
}
ll inv(ll a){return quickpow(a,MOD-2)%MOD;}
int main()
{
read(n),read(k);
fac[0]=1ll;
for(int i=1;i<=n;i++) readl(a[i]);
for(int i=1;i<=k;i++) fac[i]=fac[i-1]*i%MOD;
for(int i=1;i<=n;i++)
{
ll op=1ll;
for(int j=0;j<=k;j++)
{
sum[j]=(sum[j]+op)%MOD;
op=op*a[i]%MOD;
}
}
for(int x=1;x<=k;x++)
{
ll ans=0;
if(x&1)
{
for(int i=0;i<=x/2;i++)
{
ll c=fac[x]*inv(fac[x-i]*fac[i]%MOD)%MOD;
ll now=(sum[i]*sum[x-i]-sum[x]+MOD)%MOD;
ans=(ans+now*c%MOD)%MOD;
}
}
else
{
for(int i=0;i<x/2;i++)
{
ll c=fac[x]*inv(fac[x-i]*fac[i]%MOD)%MOD;
ll now=(sum[i]*sum[x-i]%MOD-sum[x]+MOD)%MOD;
ans=(ans+now*c%MOD)%MOD;
}
ll c=fac[x]*inv(fac[x/2]*fac[x/2]%MOD)%MOD;
ll now=(sum[x/2]*sum[x/2]%MOD-sum[x]+MOD)%MOD;
ans=(ans+now*c%MOD*499122177%MOD)%MOD;
}
printf("%d\n",ans%MOD);
}
return 0;
}
小日本(的神机果然厉害,只跑了 \(260ms\) /jk。