把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【CodeChef COUNTIT】Count Arrays(拉格朗日插值)

题目链接

  • 有一张 \(n\times m\) 的网格图,其中每个网格内填着一个 \([1,k]\) 中的正整数。
  • 定义一个长度为 \(n+m\) 的序列 \(s\),对于 \(i\in[1,n]\) 满足 \(s_i\) 为网格图第 \(i\) 行所有数的最大值,对于 \(i\in[n+1,n+m]\) 满足 \(s_i\) 为网格图第 \(i-n\) 列所有数的最大值。
  • 求有多少种可能的序列 \(s\)
  • 数据组数\(\le10^3\)\(1\le \sum n,\sum m\le10^5\)\(1\le k\le10^9\)

判定条件

首先给出结论:一个序列 \(s\) 是可能的,当且仅当 \(s_{1\sim n}\) 中的最大值和 \(s_{n+1\sim n+m}\) 中的最大值相等。

先证必要性:由于这两个最大值都等于全局最大值,肯定要相等。

再证充分性:假设第 \(x\) 行和第 \(y\) 列的最大值都是全局最大值,只要让第 \(x\) 行的每一列都填上对应列的最大值,第 \(y\) 列的每一行都填上对应行的最大值,其余位置都填 \(1\),就能构造出序列 \(s\)

拉格朗日插值

枚举全局最大值 \(i\),简单容斥就能列出答案的计算式:

\[\sum_{i=1}^k(i^{n+m}-(i-1)^ni^m-i^n(i-1)^m+(i-1)^{n+m}) \]

发现这是一个关于 \(k\)\(n+m+1\) 次多项式,可以用拉格朗日插值求解。

代码:\(O(\sum(n+m))\)

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Rg register
#define RI Rg int
#define Cn const
#define CI Cn int&
#define I inline
#define W while
#define N 100000
#define X 1000000007
using namespace std;
int n,m,c,k,f[2*N+5],Ic[2*N+5],pre[2*N+5],suf[2*N+5];
I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
int Pt,P[2*N+5],P1[2*N+5],P2[2*N+5];I void Sieve(CI S)//预处理i^n和i^m
{
	P1[1]=P2[1]=1;for(RI i=2,j;i<=S;++i) for(!P[i]&&(P[++Pt]=i,P1[i]=QP(i,n),P2[i]=QP(i,m)),
		j=1;i*P[j]<=S;++j) if(P[i*P[j]]=1,P1[i*P[j]]=1LL*P1[i]*P1[P[j]]%X,P2[i*P[j]]=1LL*P2[i]*P2[P[j]]%X,!(i%P[j])) break;
}
I void Cl() {Pt=0;for(RI i=1;i<=c;++i) P[i]=P1[i]=P2[i]=0;}
int main()
{
	RI Tt,i,t;scanf("%d",&Tt);W(Tt--)
	{
		for(scanf("%d%d%d",&n,&m,&k),Cl(),Sieve(c=n+m+1),i=1;i<=c;++i) f[i]=(f[i-1]+
			1LL*P1[i]*P2[i]-1LL*P1[i-1]*P2[i]%X-1LL*P1[i]*P2[i-1]%X+1LL*P1[i-1]*P2[i-1]+2*X)%X;//预处理前n+m+1项的值
		if(k<=c) {printf("%d\n",f[k]);continue;}
		for(t=i=1;i<=c;++i) t=1LL*t*i%X;for(t=QP(t,X-2),i=c;~i;--i) Ic[i]=t,t=1LL*t*i%X;
		for(pre[0]=i=1;i<=c;++i) pre[i]=1LL*pre[i-1]*(k-i)%X;for(suf[c+1]=1,i=c;i;--i) suf[i]=1LL*suf[i+1]*(k-i)%X;
		for(t=0,i=1;i<=c;++i) t=(t+1LL*f[i]*pre[i-1]%X*suf[i+1]%X*Ic[i-1]%X*Ic[c-i]%X*(c-i&1?X-1:1))%X;printf("%d\n",t);//拉格朗日插值
	}return 0;
}
posted @ 2022-01-22 15:49  TheLostWeak  阅读(109)  评论(0编辑  收藏  举报