【学习笔记】单位根反演

##### 基本柿子

$$
\frac{1}{n} \sum_{i=0}^{n-1} w_n^{ki} = [n|k]
$$

证明如下:

1.当$n|k$时,设$k=np$。

$\frac{1}{n} \sum_{i=0}^{n-1} w_{n}^{npi} = \frac{1}{n} \sum_{i=0}^{n-1} w_{n}^{0} = 1$

2.当$n \nmid k$时

$\frac{1}{n} \frac{w_n^{nk}-w_{n}^0}{w_n^k-1}=0$

 

##### 例题

BZOJ PYXFIB

$\sum_{i=0}^n \binom{n}{i} F_i [i\%d==0]$

$ \frac{1}{d} \sum_{i=0}^n \binom{n}{i} F_i \sum_{j=0}^{d-1} w_d^{ij}$

显然$F$要用矩乘加速

然后把$w_d^j$直接扔进去好了x

最后就是$\frac{1}{d}(w_n^j F + I)^n$

代码

//Love and Freedom.
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define inf 20021225
using namespace std;
ll read()
{
    ll s=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return f*s;
}
struct mat
{
    int a[2][2];
    mat(){}
    mat(int lu,int ru,int ld,int rd){a[0][0]=lu,a[0][1]=ru,a[1][0]=ld,a[1][1]=rd;}
    void clear(){memset(a,0,sizeof(a));}
    void det(){clear(); a[0][0]=a[1][1]=1;}
};
int G,mdn;
void upd(int &x,int y){x+=x+y>=mdn?y-mdn:y;}
mat operator+(mat a,mat b)
{
    mat tmp;
    for(int i=0;i<2;i++)    for(int j=0;j<2;j++)
        tmp.a[i][j]=(a.a[i][j]+b.a[i][j])%mdn; 
    return tmp;
}
mat operator*(mat a,mat b)
{
    mat tmp; tmp.clear();
    for(int i=0;i<2;i++)    for(int j=0;j<2;j++)
        for(int k=0;k<2;k++)    upd(tmp.a[i][j],1ll*a.a[i][k]*b.a[k][j]%mdn);
    return tmp;
}
int fac[211],tot; 
int ksm(int bs,int mi)
{
    int ans=1;
    while(mi)
    {
        if(mi&1)    ans=1ll*ans*bs%mdn;
        bs=1ll*bs*bs%mdn; mi>>=1;
    }
    return ans;
}
void getG()
{
    int top=mdn-1; tot=0;
    for(int i=1;i<=sqrt(top);i++)
        if(top%i==0)    fac[++tot]=i,fac[++tot]=top/i;
    for(G=2;G<=100;G++)
    {
        int i;
        for(i=1;i<=tot;i++)    if(fac[i]!=top&&ksm(G,fac[i])==1)    break;
        if(i>tot)    return;
    }
}
mat mksm(mat bs,ll mi)
{
    mat ans; ans.det();
    while(mi)
    {
        if(mi&1)    ans=ans*bs;
        bs=bs*bs; mi>>=1;
    }
    return ans;
}
int main()
{
    int T=read();
    while(T--)
    {
        ll n=read(),k=read(); mdn=read(); getG(); int Wn=ksm(G,(mdn-1)/k); int ans=0;
        for(int i=0;i<k;i++)
        {
            int w=ksm(Wn,i); mat cur=mksm(mat(w+1,w,w,1),n);
            int val=cur.a[0][0];
            upd(ans,val);
        }
        printf("%d\n",1ll*ans*ksm(k,mdn-2)%mdn);
    }
    return 0;
}
View Code

 

 

LOJ6485. LJJ 学二项式定理

$\frac{1}{4}\sum_{i=0}^n \sum_{j=0}^3 a_j s^i \binom{n}{i} [i\%4==j]$

$\frac{1}{4}\sum_{i=0}^n\sum_{j=0}^3 a_j s^i\binom{n}{i} [(i-j)\%4==0]$

$\frac{1}{4}\sum_{i=0}^n\sum_{j=0}^3 a_j s^i\binom{n}{i} \sum_{k=0}^3 w_4^{(i-j)k}$

$\frac{1}{4}\sum_{j=0}^3 a_j \sum_{i=0}^n s^i \binom{n}{i} \sum_{k=0}^3 w_{4}^{(i-j)k}$

$\frac{1}{4}\sum_{j=0}^3 \sum_{k=0}^3 a_j w^{-jk}(sw_{4}^k+1)^n$

然后就做完惹

//Love and Freedom.
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define inf 20021225
#define mdn 998244353
#define G 3
#define inv4 748683265
using namespace std;
ll read()
{
    ll s=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return f*s;
}
int ksm(int bs,ll mi)
{
    int ans=1;
    while(mi)
    {
        if(mi&1)    ans=1ll*ans*bs%mdn;
        bs=1ll*bs*bs%mdn; mi>>=1; 
    }
    return ans;
}
int a[4];
int main()
{
    int Wn=ksm(G,(mdn-1)/4);
    int T=read();
    while(T--)
    {
        ll n=read(); int s=read(); int ans=0;
        for(int i=0;i<4;i++)
        {
            int w=Wn,cur=0; a[i]=read();
            for(int j=0,k=1;j<4;j++,k=1ll*k*w%mdn)
                (cur+=1ll*ksm(1ll*s*k%mdn+1,n)*ksm(k,4-i)%mdn*inv4%mdn)%=mdn;
            (ans+=1ll*cur*a[i]%mdn)%=mdn;
        }
        printf("%d\n",ans);
    }
    return 0;
}
View Code
posted @ 2019-12-13 09:05  寒雨微凝  阅读(334)  评论(0编辑  收藏  举报