zoukankan      html  css  js  c++  java
  • [bzoj3601] 一个人的数论 [莫比乌斯反演+高斯消元]

    题面

    传送门

    思路

    这题妙啊

    先把式子摆出来

    $f_n(d)=sum_{i=1}n[gcd(i,n)==1]id$

    这个$gcd$看着碍眼,我们把它反演掉

    $f_n(d)=sum_{i=1}nsum_{j|i,j|n}mu(j)id=sum_{j|n}mu(j)sum_{i=1}{frac{n}{j}}(ij)d=sum_{j|n}mu(j)jdsum_{i=1}{frac{n}{j}}i^d$

    那么最后面这个东西就是个自然数幂求和了

    这篇关于斯特林数的blog最后,我给出了自然数幂求和转斯特林数的公式:

    $xn=sum_{i=1}n egin{Bmatrix} n\i end{Bmatrix} frac{x!}{(x-i)!}$

    我们对左边的$x$,取$1...m$求和,得到$sum_{i=1}^m in=sum_{j=1}m sum_{i=1}^j egin{Bmatrix} j\i end{Bmatrix} frac{j!}{(j-i)!}$

    由此可得,右边这个东西显然是一个关于$i$(也就是原来那个式子里面的$x$)的,在$1...n+1$项上有系数的多项式

    (其实还有另外一个公式:$Sum_k(n)=sum_{i=1}^n ik=sum_{j=1}kegin{Bmatrix}k\jend{Bmatrix}frac{{(n+1)}^underline{j+1}}{j+1}$)

    (好像这个简单易懂一点= =)

    不管怎么样,我们可以设$sum_{i=1}^x i^d =sum_{i=1}^{d+1}c_i x^i$

    然后我们对于$x=1...d+1$分别求出$c_i$那一项的系数,我们实际上得到了一个$d+1$元线性方程组

    可以高斯消元之,得到$c$数组

    再把$c$放进式子里面,得到:

    $f_n(d)=sum_{j|n}mu(j)jdsum_{i=1}{d+1}c_i(frac{n}{j})i=sum_{i=1}{d+1} c_i sum_{j|n}mu(j)j^d (frac{n}{j})^i$

    显然后面那个$sum$里面的一坨东西是个积性函数(因为是两个积性函数的狄利克雷卷积)对吧

    我们设$H(i)=sum_{j|i}mu(j)j^d (frac{n}{j})i$,那么$H(n)=prod_{i=1}w H(p_i^{a_i})$

    代回原式:

    $f_n(d)=sum_{i=1}^{d+1} c_i prod_{j=1}^w H(p_j{a_j})=sum_{i=1}^{d+1} c_i prod_{j=1}^w sum_{k|p_j{a_j}}mu(k)kd(frac{p_j{a_j}}{k})i$

    后面这个式子,显然当且仅当$k=1$和$k=p_j$的时候有值(因为其他时候$mu(k)=0$),那么把这个两项代入,可以得到:

    $f_n(d)=sum_{i+1}^{d+1} c_i prod_{j=1}^w (p_j^{a_jast i}-p_j^{d+a_jast i -i})$

    那么就解决了,总复杂度是$O(d^3+dw)$

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cassert>
    #include<cmath>
    #define ll long long
    #define MOD 1000000007
    using namespace std;
    inline ll read(){
    	ll re=0,flag=1;char ch=getchar();
    	while(ch>'9'||ch<'0'){
    		if(ch=='-') flag=-1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
    	return re*flag;
    }
    ll d,w,p[1010],a[1010],c[110][110],x[110];
    ll qpow(ll a,ll b){
    	ll re=1;
    	while(b){
    		if(b&1) re=re*a%MOD;
    		a=a*a%MOD;b>>=1;
    	}
    	return re;
    }
    void Gauss(){
    	ll i,j,k,num;ll tmp,tt;
    	for(i=1;i<=d+1;i++){
    		num=i;
    		for(j=i+1;j<=d+1;j++) if(abs(c[j][i])>abs(c[num][i])) num=j;
    		for(j=1;j<=d+2;j++) swap(c[i][j],c[num][j]);
    		tmp=qpow(c[i][i],MOD-2);
    		for(j=i+1;j<=d+1;j++){
    			tt=c[j][i]*tmp%MOD;
    			for(k=1;k<=d+2;k++) c[j][k]=(c[j][k]-tt*c[i][k]%MOD+MOD)%MOD;
    		}
    	}
    	for(i=d+1;i>=1;i--){
    		x[i]=c[i][d+2]=c[i][d+2]*qpow(c[i][i],MOD-2)%MOD;
    		for(j=i-1;j>=1;j--) c[j][d+2]=(c[j][d+2]-c[j][i]*c[i][d+2]%MOD+MOD)%MOD;
    	}
    }
    int main(){
    	d=read();w=read();ll i,j,tmp,sum=0;
    	for(i=1;i<=w;i++) p[i]=read(),a[i]=read();
    	for(i=1;i<=d+1;i++){
    		tmp=1;sum+=qpow(i,d);sum%=MOD;
    		for(j=1;j<=d+1;j++){
    			tmp=tmp*i%MOD;
    			c[i][j]=tmp;
    		}
    		c[i][d+2]=sum;
    	}
    	Gauss();tmp=0;
    	for(i=1;i<=d+1;i++){
    		sum=1;
    		for(j=1;j<=w;j++) sum*=(qpow(p[j],a[j]*i)-qpow(p[j],d+a[j]*i-i)+MOD),sum%=MOD;
    		tmp=(tmp+x[i]*sum)%MOD;
    	}
    	printf("%lld
    ",tmp);
    }
    
  • 相关阅读:
    0121 集合类 ArrayList 的练习
    0121 有关接口的使用练习
    泛型相关知识
    0120 父类与子类创建、重写及转型练习
    0118练习 单例模式
    java设计模式 略版
    0117 面向对象OOP有关方法、类、构造方法及权限修饰符的练习
    0115 创建类并调用
    [luogu P2586] GCD 解题报告 (莫比乌斯反演|欧拉函数)
    POJ1284 Primitive Roots (原根)
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/9439622.html
Copyright © 2011-2022 走看看