Loading

我们仍未知道那天所看见的题的解法 - 3

CF622F The Sum of the k-th Powers

【分析过程】

\(\sum\limits_{i=1}^ni^k\)?超级简单傻逼题,容我慢慢打个快速幂,\(O(n\lg k)\) 秒了

傻逼竟是我自己

首先对于 \(\sum\limits_{i=1}^ni^k\),这叫做自然数幂之和,在具体数学的伯努利数那一节出现过,可以证明答案是 \(k+1\) 次方的多项式

这里我们不用伯努利数,我们用2020省选中那个东西

仿照2020省选A卷中普通幂转下降幂

\[k^p\binom{n}{k}=\sum\limits_{i=1}^p\begin{Bmatrix}p\\i\end{Bmatrix}\binom{n-i}{k-i}n^\underline{i} \]

这里也有个关于阶乘转下降幂的恒等式

\[i^k=\sum_{j=1}^k\begin{Bmatrix}k\\j\end{Bmatrix}i^\underline{j} \]

这在具体数学中有证明,但在我证明完毕之前并没有看到(也就是说刚证出来就看见了QAQ,它那里证的比我简洁,是巨简洁)

接下来我们自己来使用数学归纳法证一下

显然当 \(k=1,k=2\) 时成立,将 \(i^k\)\(i^{k-1}\) 做差,也就是说我们只需要证明

\[\begin{align*} i^k-i^{k-1}&=i^{k-1}(i-1) \\ &= \sum\limits_{j=1}^{k-1}\begin{Bmatrix}k\\j\end{Bmatrix}i^\underline{j}+i^\underline k \end{align*} \]

这东西显然是可以双向推出的,于是我们不关心从哪个方向证明

\[\begin{align*} &= \sum\limits_{j=1}^{k-1}\begin{Bmatrix}k\\j\end{Bmatrix}i^\underline{j}+i^\underline k \\ &= \sum\limits_{j=1}^{k-2}\begin{Bmatrix}k-1\\j\end{Bmatrix}i^\underline{j+1}+\sum\limits_{j=1}^{k-1}(j-1)\begin{Bmatrix}k-1\\j\end{Bmatrix}i^\underline j+i^\underline k \\ &= \sum\limits_{j=1}^{k-2}(i-j)\begin{Bmatrix}k-1\\j\end{Bmatrix}i^\underline{j}+\sum\limits_{j=1}^{k-2}(j-1)\begin{Bmatrix}k-1\\j\end{Bmatrix}i^\underline j+i^\underline k+(k-2)i^\underline{k-1} \\ &=(i-1)\sum\limits^{k-1}_{j=1}+i^\underline k+(k-2)i^\underline{k-1}+(i-1)i^\underline{k-1} \\ &=(i-1)\sum\limits^{k-1}_{j=1} \\ &=(i-1)i^{k-1} \end{align*} \]

即得:

\[i^k=\sum_{j=1}^k\begin{Bmatrix}k\\j\end{Bmatrix}i^\underline{j}=\sum_{j=1}^k\begin{Bmatrix}k\\j\end{Bmatrix}\dbinom{i}{j}j! \]

\(S(n)=\sum\limits_{i=1}^ni^k\),应用上指标求和:

\[\begin{align*} S(n)&=\sum\limits_{i=1}^ni^k \\ &=\sum\limits_{i=1}^n\sum_{j=1}^k\begin{Bmatrix}k\\j\end{Bmatrix}\dbinom{i}{j}j! \\ &=\sum_{j=1}^k\begin{Bmatrix}k\\j\end{Bmatrix}j!\sum\limits_{i=1}^n\dbinom{i}{j} \\ &=\sum_{j=1}^k\begin{Bmatrix}k\\j\end{Bmatrix}\dfrac{(n+1)^\underline{j+1}}{j+1} \end{align*} \]

我们并不关心这个多项式是什么,我们只要知道它在 \(S(n)\) 下的取值

于是我们可以直接找出 \(k+2\) 个点,暴力拉格朗日插值即可得出答案

但是这样复杂度就会爆炸,然后你需要多项式快速插值

观察拉格朗日插值的式子:

\[f(k)=\sum\limits_{i=1}^ny_i\prod_{j\ne i}\dfrac{k-x_j}{x_i-x_j} \]

我们发现复杂度的瓶颈在后面的 \(\prod\) 上,这道题并没有给我们点值,所以我们可以自己决定

于是我们可以选取一段 \(x\) 连续的 \(k+2\) 个点值,此时式子变为

\[f(k)=\sum\limits_{i=1}^ny_i\prod_{j\ne i}\dfrac{k-x_j}{x_i-x_j} = \sum\limits_{i=1}^n(-1)^{n-i}y_i\dfrac{\prod\limits_{j=1}^{i-1}(k-j)\prod\limits_{j=i+1}^{n}(k-j)}{(i-1)!(n-i)!}=\sum\limits_{i=1}^n(-1)^{n-i}y_i\dfrac{(k-1)^{\underline n}}{(i-1)!(n-i)!(k-i)} \]

对于分子进行预处理之后,直接上 \(\text{Lagrange}\) 插值即可

【代码实现】

#include<bits/stdc++.h>
#define fx(l,n) inline l n
#define int long long

const int mod=1e9+7,N=1200000;

int n,k,fac[N],sum[N],bf,ans,low[N],inv[N],dinv[N];
fx(int,gi)(){
	char c=getchar();int s=0,f=1;
	while(c>'9'||c<'0'){
		if(c=='-') f=-f;
		c=getchar();
	}
	while(c<='9'&&c>='0') s=(s<<3)+(s<<1)+(c-'0'),c=getchar();
	return s*f;
}
fx(int,fpow)(int a,int b=mod-2){
	int sum=1;
	while(b){
		if(b&1) (sum*=a)%=mod;
		(a*=a)%=mod;
		b>>=1;
	} return sum;
}
signed main(){
	n=gi(),k=gi();fac[0]=1;
	for(int i=1;i<=k+10;i++) fac[i]=fac[i-1]*i%mod;
	inv[k+2]=fpow(fac[k+2]);
	for(int i=k+1;~i;i--) inv[i]=inv[i+1]*(i+1)%mod;
	for(int i=1;i<=k+2;i++) sum[i]=(sum[i-1]+fpow(i,k))%mod;
	if(n<=k+2) return printf("%lld",sum[n]),0;
	low[1]=n-1;
	for(int i=2;i<=k+2;i++) low[i]=low[i-1]*(n-i)%mod;
	for(int i=1;i<=k+2;i++) dinv[i]=fpow(n-i);
	for(int i=1;i<=k+2;i++){
		bf=sum[i]*inv[i-1]%mod*inv[k-i+2]%mod*dinv[i]%mod;
		if((k+2-i)&1) ans+=mod-bf;
		else ans+=bf;
		ans%=mod;
	}
	printf("%lld",ans*low[k+2]%mod);
}

CF576D Flights for Regular Customers

【分析过程】

一个经典题目

首先这题不能直接矩阵快速幂,因为边有限制

考虑到边并不是很多,于是我们可以分开进行快速幂

也就是说每次加边,然后快速幂直到下一条边的限制解除,然后以此类推

考虑乘法过程即为:\(ans\times m\times m\times\cdots\times m\),加边,继续乘 \(m\)

于是乎 \(ans\) 矩阵可以不用每次重置

对于每次快速幂后,判断可达性,之后跑个最短路更新一下答案

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<bitset>
#define N 1000001
#define M 201
#define INF 20000000000
#define Kafuu return
#define Chino 0
#define fx(l,n) inline l n
#define set(l,n,ty,len) memset(l,n,sizeof(ty)*len)
#define cpy(f,t,ty,len) memcpy(t,f,sizeof(ty)*len)
#define int long long
#define R register
#define C const
using namespace std;
int n,m,last,dis[M][M],ans=INF;
struct matrix{
	bitset<M>m[M];
	fx(matrix,operator) * (const matrix &b) const{
		matrix c;
		for(int i=1;i<=n;i++){
			for(int o=1;o<=n;o++) c.m[i][o]=0;
			for(int o=1;o<=n;o++){
				if(m[i][o]) c.m[i]|=b.m[o];
			}
		}
		return c;
	}
}ma,dw;
struct Edge{
	int f,t,tms;
}e[N];
fx(bool,cmp)(Edge a,Edge b){
	return a.tms<b.tms;
}
fx(int,gi)(){
	R char c=getchar();R int s=0,f=1;
	while(c>'9'||c<'0'){
		if(c=='-') f=-f;
		c=getchar();
	}
	while(c<='9'&&c>='0') s=(s<<3)+(s<<1)+(c-'0'),c=getchar();
	return s*f;
}
fx(void,pow)(int b){
	while(b){
		if(b&1) dw=dw*ma;
		ma=ma*ma;
		b>>=1;
	}
}
fx(void,stcmt)(int b){
	for(int i=1;i<=n;i++){
		for(int o=1;o<=n;o++){
			dis[i][o]=(i==o?0:INF);
		}
	}
	for(int i=1;i<=b;i++) dis[e[i].f][e[i].t]=1;
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			for(int o=1;o<=n;o++){
				dis[i][o]=min(dis[i][o],dis[i][k]+dis[k][o]);
			}
		}
	}
}
signed main(){
	n=gi(),m=gi();
	for(int i=1;i<=m;i++){
		e[i].f=gi(),e[i].t=gi();e[i].tms=gi();
	}
	for(int i=0;i<=n;i++) dw.m[i][i]=1;
	sort(e+1,e+m+1,cmp);
	for(int i=1;i<=m;i++){
		for(int o=1;o<=n;o++) ma.m[o].reset();
		for(int o=1;o<i;o++) ma.m[e[o].f][e[o].t]=1;
		pow(e[i].tms-e[i-1].tms);
		stcmt(i);
		for(int o=1;o<=n;o++){
			if(dw.m[1][o]) ans=min(ans,e[i].tms+dis[o][n]);
		}
	}
	if(ans==INF) printf("Impossible");
	else printf("%d",ans);
}
posted @ 2021-03-16 17:11  zythonc  阅读(60)  评论(0编辑  收藏  举报