[bzoj3601] 一个人的数论 [莫比乌斯反演+高斯消元]

题面

传送门

思路

这题妙啊

先把式子摆出来

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

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

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

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

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

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

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

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

(其实还有另外一个公式:$Sum_k(n)=\sum_{i=1}^n i^k=\sum_{j=1}^k\begin{Bmatrix}k\\j\end{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)j^d\sum_{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)k^d(\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_j\ast i}-p_j^{d+a_j\ast 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\n",tmp);
}

原文地址:https://www.cnblogs.com/dedicatus545/p/9439622.html

时间: 2024-08-04 00:47:33

[bzoj3601] 一个人的数论 [莫比乌斯反演+高斯消元]的相关文章

【bzoj3601】一个人的数论 莫比乌斯反演+高斯消元

题目描述 题解 莫比乌斯反演+高斯消元 (前方高能:所有题目中给出的幂次d,公式里为了防止混淆,均使用了k代替) #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const ll mod = 1000000007; ll a[110][110] , p[1010] , v[1010]; ll pow(ll x , ll

BZOJ 3601 一个人的数论 莫比乌斯反演+高斯消元

题目大意:求Σ[i|n]i^d 围观题解:http://www.cnblogs.com/jianglangcaijin/p/4033399.html 果然我还是太蒻了- - 此外Σ[1<=i<=n]i^m的零次项注定为0- - 所以常数项不用消了- - #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 110 #defin

[数论] 高斯消元(整型和浮点型)

高斯消元法: 数学上,高斯消元法(或译:高斯消去法)(英语:Gaussian Elimination),是线性代数中的一个算法,可用来为线性方程组求解,求出矩阵的秩,以及求出可逆方阵的逆矩阵.当用于一个矩阵时,高斯消元法会产生出一个"行梯阵式".(来自维基百科) 构造如下方程: a[0][0]*X0 + a[0][1] *X1 + a[0][2]*X2+...........a[0][n-1]*Xn-1   =  a[0][n] a[1][0]*X0 + a[1][1] *X1 + a

poj_1222_高斯消元

第一次学习使用高斯消元,将灯板化为线性方程组,进行求解. /*######################################################################### # File Name: poj_1222.cpp # Author: CaoLei # Created Time: 2015/7/20 15:48:04 ###################################################################

HDU 4870 Rating(高斯消元)

HDU 4870 Rating 题目链接 题意:一个人注册两个账号,初始rating都是0,他每次拿低分的那个号去打比赛,赢了加50分,输了扣100分,胜率为p,他会打到直到一个号有1000分为止,问比赛场次的期望 思路:f(i, j)表示i >= j,第一个号i分,第二个号j分时候,达到目标的期望,那么可以列出转移为f(i, j) = p f(i', j') + (1 - p) f(i'' + j'') + 1 f(i', j')对应的是赢了加分的状态,f(i'', j'')对应输的扣分的状态

【BZOJ 4171】 4171: Rhl的游戏 (高斯消元)

4171: Rhl的游戏 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 74  Solved: 33[Submit][Status][Discuss] Description RHL最近迷上一个小游戏:Flip it.游戏的规则很简单,在一个N*M的格子上,有一些格子是黑色,有一些是白色 .每选择一个格子按一次,格子以及周围边相邻的格子都会翻转颜色(边相邻指至少与该格子有一条公共边的格子 ),黑变白,白变黑.RHL希望把所有格子都变成白色的.不幸

POJ 1830 开关问题 高斯消元,自由变量个数

http://poj.org/problem?id=1830 如果开关s1操作一次,则会有s1(记住自己也会变).和s1连接的开关都会做一次操作. 那么设矩阵a[i][j]表示按下了开关j,开关i会被操作一次,记得a[i][i] = 1是必须的,因为开关i操作一次,本身肯定会变化一次. 所以有n个开关,就有n条方程, 每个开关的操作次数总和是:a[i][1] + a[i][2] + ... + a[i][n] 那么sum % 2就代表它的状态,需要和(en[i] - be[i] + 2) % 2

BZOJ 3105: [cqoi2013]新Nim游戏 [高斯消元XOR 线性基]

以后我也要用传送门! 题意:一些数,选择一个权值最大的异或和不为0的集合 终于有点明白线性基是什么了...等会再整理 求一个权值最大的线性无关子集 线性无关子集满足拟阵的性质,贪心选择权值最大的,用高斯消元判断是否和已选择的线性相关 每一位记录pivot[i]为i用到的行 枚举要加入的数字的每一个二进制为1的位,如果有pivot[i]那么就异或一下(消元),否则pivot[i]=这个数并退出 如果最后异或成0了就说明线性相关... #include <iostream> #include &l

[bzoj1013][JSOI2008]球形空间产生器sphere-题解[高斯消元]

Description 有一个球形空间产生器能够在n维空间中产生一个坚硬的球体.现在,你被困在了这个n维球体中,你只知道球面上n+1个点的坐标,你需要以最快的速度确定这个n维球体的球心坐标,以便于摧毁这个球形空间产生器. Input 第一行是一个整数n(1<=N=10).接下来的n+1行,每行有n个实数,表示球面上一点的n维坐标.每一个实数精确到小数点后6位,且其绝对值都不超过20000. Output 有且只有一行,依次给出球心的n维坐标(n个实数),两个实数之间用一个空格隔开.每个实数精确到