loj6485 LJJ学二项式定理
shadowice1984 · · 个人记录
单位根反演苟逼题……
题意简单明了算数
求
膜998244353的值
其中
这题不知道单位根反演的就凉了……
然后简单的说一下思路
首先我们发现由于
说白了就是求
这个东西的值
接下来的操作就是生成函数那一套理论了……(生成函数真是万能)
我们发现要求的式子和这个式子非常像
然后由于需要使用生成函数我们把他搞成形式幂级数(这个词仅仅装x用,不理解也没关系)的形式
也就是在每一项后面补一个
但是显然这个式子不能表示成一个简单易懂的多项式
所以考虑求这个数列翻转之后的对应的多项式是什么
这是什么?二项式定理啊!题目都提醒你了!
所以
好了这东西有什么用呢?
还记得ntt/fft吗?还记得ntt/fft最后一步点值表达转成系数表达的时候证明了什么吗?
你肯定忘了
各大博客的证明都是根据这个式子证明出来的
即n是k的倍数的时候上面的式子是1否则是0
这个式子的证明也不是很难,就是套一波等比数列求和公式即可~
然而这个东西其实非常重要……(但是学ntt的时候绝对是忙着抄板子了)
因为通过上边那个式子,我们可以搞出一个被称为单位根反演的非常nb的东西
大概长这样
若
则
证明?
把左边式子中的
然后我们有
交换一下求和号
如果我们令
则有
代入一下就得到了
简单来说,比如说我们要求这个多项式第0,4,8,12,16,……项系数的和,那么我们就只需要计算
然后我们要求的是
把整个序列倒过来得到
然后稍作调整
接下来假设我们只求d=0时式子的值
换句话说就是
似乎可以直接套刚才的公式?
其中
很好,快速幂就能搞定了!
问题来了要是i膜4余1,2,3而不是余0呢?
抱歉,不会
其实是有办法做的
我们的确只能处理i是4的倍数时这些系数的和
但是……,我们可以想办法把余某一个数变成膜4为0
比如说,我们将这个多项式整体平移一位,这样原来余1的项就变成了膜4为0 的项,接下来就可以用之前的套路了
那么多项式怎么平移一位呢?
乘x啊
所以最后答案就变成了
搞定……
不要惊讶,我们的每一步推理都是有理有据的
所以尽管这两个和式没啥关系,但是算出来的数字确实是一样的……
于是我们成功将一个
直接愉快的快速幂就行了~
数学真珂啪还是学OI好了
代码极短
上代码~
#include<cstdio>
#include<algorithm>
using namespace std;typedef long long ll;const ll mod=998244353;
inline ll po(ll a,ll p){ll r=1;for(;p;p>>=1,a=a*a%mod)if(p&1)r=r*a%mod;return r;}
ll w[4]={1,911660635,998244352,86583718};ll a[4];ll s;ll res;ll n;ll f[4];int T;
int main()
{
scanf("%d",&T);
for(int z=1;z<=T;z++)
{
scanf("%lld%lld%lld%lld%lld%lld",&n,&s,&a[0],&a[1],&a[2],&a[3]);
for(int i=0;i<4;i++)f[i]=po((w[i]+s)%mod,n);res=0;
for(int i=0;i<4;i++)
{
ll ret=0;for(int j=0;j<4;j++)(ret+=f[j])%=mod;
for(int j=0;j<4;j++)(f[j]*=w[j])%=mod;(res+=ret*a[(n+i)%4])%=mod;
}printf("%lld\n",res*748683265%mod);
}return 0;
}