loj6485 LJJ学二项式定理

shadowice1984

2018-08-13 20:36:18

Personal

单位根反演苟逼题…… _________ 题意简单明了算数 求 $$\sum_{i=0}^{n}C_{n}^{i}S^{i}A_{i\%4}$$ 膜998244353的值 其中$n<10^{18}$ 这题不知道单位根反演的就凉了…… 然后简单的说一下思路 首先我们发现由于$a_{0},a_{1},a_{2},a_{4}$都是输入的所以说我们肯定是分情况讨论一波,每个a后边是单独算的 说白了就是求 $$\sum_{d=0}^{3}A_{d}\sum_{i=0}^{n}C_{n}^{i}S^{i}[i\%4==d]$$ 这个东西的值 接下来的操作就是生成函数那一套理论了……(生成函数真是万能) 我们发现要求的式子和这个式子非常像 $$\sum_{i=0}^{n}C_{n}^{i}S^{i}$$ 然后由于需要使用生成函数我们把他搞成形式幂级数(这个词仅仅装x用,不理解也没关系)的形式 也就是在每一项后面补一个$x^{i}$这样,这个数列就变成了一只多项式 $$\sum_{i=0}^{n}C_{n}^{i}S^{i}x^{i}$$ 但是显然这个式子不能表示成一个简单易懂的多项式 所以考虑求这个数列翻转之后的对应的多项式是什么 $$\sum_{i=0}^{n}C_{n}^{i}S^{n-i}x^{i}$$ 这是什么?二项式定理啊!题目都提醒你了! 所以 $$(x+S)^{n}=\sum_{i=0}^{n}C_{n}^{i}S^{n-i}x^{i}$$ 好了这东西有什么用呢? 还记得ntt/fft吗?还记得ntt/fft最后一步点值表达转成系数表达的时候证明了什么吗? ~~你肯定忘了~~ 各大博客的证明都是根据这个式子证明出来的 $$\frac{1}{n}\sum_{j=0}^{n-1}(\omega_{n}^{k})^{j}=[n|k]$$ 即n是k的倍数的时候上面的式子是1否则是0 这个式子的证明也不是很难,就是套一波等比数列求和公式即可~ 然而这个东西其实非常重要……~~(但是学ntt的时候绝对是忙着抄板子了)~~ 因为通过上边那个式子,我们可以搞出一个被称为单位根反演的非常nb的东西 大概长这样 若 $$f(x)=\sum_{i=0}^{n}a_{i}x^{i}$$ 则 $$\sum_{i=0}^{n}a_{i}[i|d]=\frac{1}{d}\sum_{p=0}^{d-1}f(\omega_{d}^{p})$$ 证明? 把左边式子中的$[i|d]$换成 $$\frac{1}{d}\sum_{j=0}^{d-1}(\omega_{d}^{i})^{j}$$ 然后我们有 $$\frac{1}{d}\sum_{i=0}^{n}a_{i}\sum_{j=0}^{d-1}(\omega_{d}^{i})^{j}$$ 交换一下求和号 $$\frac{1}{d}\sum_{j=0}^{d-1}\sum_{i=0}^{n}a_{i}(\omega_{d}^{i})^{j}$$ 如果我们令$f(x)$中的表达式中的$x=\omega_{d}^{i}$ 则有 $$f(\omega_{d}^{i})=\sum_{i=0}^{n}a_{i}(\omega_{d}^{i})^{j}$$ 代入一下就得到了 $$\sum_{i=0}^{n}a_{i}[i|d]=\frac{1}{d}\sum_{p=0}^{d-1}f(\omega_{d}^{p})$$ 简单来说,比如说我们要求这个多项式第0,4,8,12,16,……项系数的和,那么我们就只需要计算 $$ \frac{1}{4}(f(\omega_{4}^{0})+f(\omega_{4}^{1})+f(\omega_{4}^{2})+f(\omega_{4}^{3}))$$的值即可 好了如果你还没有懵逼的话 我们继续接下来的推倒过程 设 $$f(x)=(x+S)^{n}=\sum_{i=0}^{n}C_{n}^{i}S^{n-i}x^{i}$$ 然后我们要求的是 $$\sum_{d=0}^{3}A_{d}\sum_{i=0}^{n}C_{n}^{i}S^{i}[i\%4==d]$$ 把整个序列倒过来得到 $$\sum_{d=0}^{3}A_{d}\sum_{i=0}^{n}C_{n}^{i}S^{n-i}[(n-i)\%4==d]$$ 然后稍作调整 $$\sum_{d=0}^{3}A_{(n+d)\%4}\sum_{i=0}^{n}C_{n}^{i}S^{n-i}[i\%4==d]$$ 接下来假设我们只求d=0时式子的值 $$A_{n\%4}\sum_{i=0}^{n}C_{n}^{i}S^{n-i}[i\%4==0]$$ 换句话说就是 $$A_{n\%4}\sum_{i=0}^{n}C_{n}^{i}S^{n-i}[i|4]$$ 似乎可以直接套刚才的公式? $$\frac{1}{4}A_{n\%4}(f(\omega_{4}^{0})+f(\omega_{4}^{1})+f(\omega_{4}^{2})+f(\omega_{4}^{3}))$$ 其中$f(x)=(x+s)^{n}$ 很好,快速幂就能搞定了! 问题来了要是i膜4余1,2,3而不是余0呢? ~~抱歉,不会~~ 其实是有办法做的 我们的确只能处理i是4的倍数时这些系数的和 但是……,我们可以想办法把余某一个数变成膜4为0 比如说,我们将这个多项式整体平移一位,这样原来余1的项就变成了膜4为0 的项,接下来就可以用之前的套路了 那么多项式怎么平移一位呢? ~~乘x啊~~ 所以最后答案就变成了 $$\frac{1}{4}\sum_{d=0}^{3}A_{(n+d)\%4}\sum_{i=0}^{3}f(\omega_{4}^{i})(\omega_{4}^{i})^{d}$$ $$\frac{1}{4}\sum_{d=0}^{3}A_{(n+d)\%4}\sum_{i=0}^{3}(\omega_{4}^{i}+S)^{n}(\omega_{4}^{i})^{d}$$ 搞定…… 不要惊讶,我们的每一步推理都是有理有据的 所以尽管这两个和式没啥关系,但是算出来的数字确实是一样的…… 于是我们成功将一个$O(nlogn)$的式子强行化成了$O(logn)$的式子 直接愉快的快速幂就行了~ ~~数学真珂啪还是学OI好了~~ ~~代码极短~~ 上代码~ ```C #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; } ```