loj 6485
单位根反演好题
题意:求$\sum_{i=0}^{n}C_{n}^{i}S^{i}a_{ i mod 4 }$
看到$i$ $mod$ $4$这种东西,很显然要分类讨论啦
于是变成了这种形式:
$\sum_{d=0}^{3}a_{d}\sum_{i=0}^{n}[$ $i\equiv d$ $mod$ $4$]$C_{n}^{i}S^{i}$
前面暂时先不管,如果不考虑到取模的限制,发现我们实际只是在求这个东西
$\sum_{i=0}^{n}C_{n}^{i}S^{i}$
写成形式幂级数(生成函数)的形式,就是这样:
$\sum_{i=0}^{n}C_{n}^{i}S^{i}x^{i}$
感觉有点像二项式定理,把原式改写成这个形式:
$\sum_{i=0}^{n}C_{n}^{n-i}S^{n-i}$
再去构造生成函数,也就是:
$\sum_{i=0}^{n}C_{n}^{n-i}S^{n-i}x^{i}$
这就是二项式定理了嘛
也就是:
$(x+S)^{n}=\sum_{i=0}^{n}C_{n}^{n-i}S^{n-i}x^{i}$
可是没有什么帮助吧...
其实是有的!
不要忘了单位根反演的表达式:
若$f(x)=\sum_{i=0}^{n}a_{i}x^{i}$,则$\sum_{i=0}^{n}a_{i}[d|i]=\frac{1}{d}\sum_{p=0}^{d-1}f(w_{d}^{p})$
那么我们看到,当模4等于0时,所求的部分即为$\sum_{i=0}^{n}C_{n}^{n-i}S^{n-i}[4|i]$
那么也就是$\frac{1}{4}\sum_{i=0}^{3}f(w_{4}^{i})$
这样这一部分就...算完了
可是$mod$ $4$不为0的部分怎么办呢?
多项式平移啊!
我们整体乘一个$x$,这样现在模$4$为0的项就是原来模$4$为1的项了嘛(不要忘了我们已经反转了系数!)
这样就可做了
最后的表达式即为$\frac{1}{4}\sum_{d=0}^{3}a_{(n+d)mod 4}\sum_{p=0}^{3}(w_{4}^{p})^{d}f(w_{4}^{p})$
最后也就是$\frac{1}{4}\sum_{d=0}^{3}a_{(n+d)mod 4}\sum_{p=0}^{3}(w_{4}^{p})^{d}(w_{4}^{p}+S)^{n}$
代码也就很好写了
#include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #include <queue> #include <stack> #define ll long long using namespace std; const ll mode=998244353; ll f[4]; ll w[4]; ll a[4]; int T; ll n,S; ll pow_mul(ll x,ll y) { ll ret=1; while(y) { if(y&1)ret=ret*x%mode; x=x*x%mode,y>>=1; } return ret; } int main() { w[0]=1; for(int i=1;i<=3;i++)w[i]=w[i-1]*pow_mul(3,(mode-1)/4)%mode; scanf("%d",&T); while(T--) { scanf("%lld%lld",&n,&S); for(int i=0;i<=3;i++)scanf("%lld",&a[i]); for(int i=0;i<=3;i++)f[i]=pow_mul(w[i]+S,n); ll ans=0; for(int i=0;i<=3;i++) { ll s=0; for(int j=0;j<=3;j++)s+=f[j],s%=mode; for(int j=0;j<=3;j++)f[j]=f[j]*w[j]%mode; s=s*a[(n+i)%4]%mode; ans=(ans+s)%mode; } printf("%lld\n",ans*pow_mul(4,mode-2)%mode); } return 0; }