前言
蒟蒻代码惨遭卡常,根本跑不过
前置芝士——单位根反演
单位根有这样的性质:
[frac{1}{n}sum_{i=0}^{n-1}omega_{n}^{ki}=left[n|k
ight]
]
所以可以得出单位根反演的式子
如果有(f(x)=sum_{i=0}a_ix^i),就可以推出
[sum_{i=0}^na_ileft[d|i
ight]=frac{1}{d}sum_{p=0}^{d-1}f(omega_d^p)
]
证明可以把上面的式子代入,然后交换和号
思路
这道题要求的东西是这样的
[sum_{i=0}^3a_isum_{j=0}^nleft(egin{matrix}n\jend{matrix}
ight)s^jleft[j\%4=i
ight]
]
写出(sum_{j=0}^nleft(egin{matrix}n\jend{matrix}
ight)s^j)的生成函数,由二项式定理得到是((sx+1)^n)
不妨设i=0
则要求
[sum_{j=0}^nleft(egin{matrix}n\jend{matrix}
ight)s^jleft[4|j
ight]
]
直接套公式
原式等于
[frac{1}{4}sum_{p=0}^3f(omega_4^p)
]
对于i等于1,2,3,相当于原式向右边“移动”了1,2,3个位置
乘以自变量的对应倍即可
代码
蒟蒻的代码不知道为什么跑的辣么慢,只有60pts
#include <cstdio>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
int T,a[4],s,n,MOD=998244353,W[5]={1,911660635,998244352,86583718},inv=748683265;
int pow(int a,int b){
int ans=1;
while(b){
if(b&1)
ans=(ans*a)%MOD;
a=(a*a)%MOD;
b>>=1;
}
return ans;
}
signed main(){
scanf("%lld",&T);
while(T--){
scanf("%lld %lld %lld %lld %lld %lld",&n,&s,&a[0],&a[1],&a[2],&a[3]);
int ans=0;
for(int i=0;i<4;i++){
int mid=0;
for(int j=0;j<4;j++)
mid=(mid+pow((s*W[j]%MOD+1%MOD)%MOD,n)*pow(W[i*j%4],MOD-2)%MOD)%MOD;
ans=(ans+a[i]*mid%MOD*inv%MOD)%MOD;
}
printf("%lld
",ans);
}
return 0;
}