「NOI2019」机器人 拉格朗日插值

「NOI2019」机器人 拉格朗日插值

Part 20

爆搜,单调栈检查方案即可。

期望得分 20

Part 35-50

考虑一个性质。

对于一个序列 \(H\)。我们找到其中高度最大的那一个(如果有多个最大的取位置最右边的)。

设这个位置为 \(pos\)。容易发现 \(pos\) 左边的不能到 \(pos\) 右边,而 \(pos\) 右边的不能到 \(pos\) 左边。

而且 \([1,pos-1],[pos+1,n]\) 这两段区间长度的绝对值之差不能大于 \(2\)

我们发现 \(pos\) 相当于就是将一段序列切割出来了。

那么我们可以考虑区间 dp。设 \(f_{i,j}(x)\) 表示 \([i,j]\) 这段区间中高度最大为 \(x\) 且满足题目所给条件的方案数。

转移:

\[f_{i,j}(x)=\sum_Sf_{i,pos-1}(S)\times \sum_Tf_{pos+1,j}(T) \]

枚举满足条件的 \(pos\)。用前缀和能优化到 \(O(1)\) 转移。

期望得分:35

发现 \(pos\) 的位置只有几个,所以所有的状态数不会很多,由于 \(pos\) 在中点左右的位置,猜想只有 \(O(n\log n)\) 个区间数是有用的。爆搜一下发现 \(n=300\) 时有 \(3000\) 不到的有用区间数,差不多是 \(10n\) 的样子。那么给每个区间标号后最多有 \(3000\times B\) 个状态需要转移。

期望得分:50

Part 60

注意到 \(f_{i,j}(x)\) 的初值。

\[f_{i,i}(x)=\left\{ \begin{aligned} 0& &j<A_i \\ 1& &j\in[A_i,B_i]\\ 0& &j>B_i \end{aligned} \right. \]

可以把它看做一个分段的多项式。\(1\)\(x^0\)

那么我们发现 \(f_{i,j}(x)\) 就是若干个多项式之积,不难推知其度为 \(j-i\)

考虑 \(A_i=1,B_i=10^9\) 的部分分。

那么 \(f_{i,i}(x)\) 的初值一定为 \(1\)

也就是在该约束下我们的多项式只有一段。

而我们要求 \(\sum f_{1,n}(x)\)

我们知道任意一个度为 \(n\) 的多项式的前缀和是一个度为 \(n+1\) 的多项式。

所以我们直接上拉格朗日插值。即可求得。

(前 60 分的代码在正解下面也放了)

Part 100

根据 Part 60 的部分我们已经知道 \(f_{i,j}(x)\) 是一个多项式了。

注意到 \(n\) 一共只有 \(300\)。也就是说这个分段多项式最多只有 \(2n\) 段的样子。

我们将区间设成左闭右开方便处理。

假设我们求出了 \([1,C_{i})\)\(f_{i,j}(x)\) 的前缀和,考虑求得 \(\sum f_{i,j}(x),x\in[C_i,C_{i+1}]\) 的值。

如果区间长度小于等于 \(n+1\)。因为我们有了之前的前缀和,直接暴力 dp 出\(f_{i,j}(x),x\in[C_i,C_{i+1})\) 即可。

如果区间大于 \(n+1\) 。我们考虑暴力 dp 出 \(f_{i,j}(x),x\in[C_i,C_i+n]\) 。然后根据这 \(n\) 个点我们插值求得 \(\sum f_{i,j}(x),(x\in [C_i,C_i+n])\) 的多项式(其前缀和的多项式),然后计算出 \(\sum f_{i,j}(C_{i+1}-1)\) 即可。

然后继续处理下一段。由于 \(x\) 值我们可以选连续的,所以可以做到 \(O(n)\) 插值。

那么总复杂度是 \(O(10\times n^3)\)

常数较大。考虑优化常数,我们发现通过插值求 \(f_{i,j}(x)\) 的时候,只需要插 \(i-j+2\) 个点就行,不需要插 \(n+1\) 个点。取模也同样可以优化。以及可以预处理的都预处理一下,比如逆元啥的,不然可能快速幂求逆元会成为瓶颈。

最后代码如下:(插值的时候怕错多插了几个点)

#include<bits/stdc++.h>
#define ll long long
#define Mod(x) ((x>=MOD)&&(x-=MOD))
using namespace std;
const int MOD = 1e9+7;
const int MAXN = 305;
int A[MAXN],B[MAXN],n;
int tot,id[305][305],m,siz,MX,T,L[2500],R[2500];
ll f[2500][305],C[MAXN<<1],fac[MAXN],df[MAXN],inv[MAXN],pre[MAXN];
bool vis[MAXN][MAXN];
ll qpw(ll x,ll b)
{
	ll r=1;
	for(;b;b>>=1,x=x*x%MOD) if(b&1) r=r*x%MOD;
	return r;
}
vector < pair<int,int> > vec;
map< pair<int,int> ,bool >mp;
void init(int l,int r)
{
	if(id[l][r]) return ;
	if(l>r)
	{
		if(!mp.count(make_pair(l,r)))vec.push_back(make_pair(l,r));
		mp[make_pair(l,r)]=1;
		return ;
	}
	id[l][r]=++tot;
	for(int i=l;i<=r;++i) if(abs(2*i-l-r)<=2)
		init(l,i-1),init(i+1,r);
}
void dfs(int l,int r)
{
	if(vis[l][r]) return ;
	vis[l][r]=1;int cur=id[l][r];
	if(l>r) f[cur][0]=1;
	else
	{
		for(int i=max(l,(l+r)/2-1);i<=min(r,(l+r)/2+1);++i)
		{	
			if(abs(2*i-l-r)<=2&&A[i]<=T&&T<B[i])
			{
				dfs(l,i-1);dfs(i+1,r);
				int u=id[l][i-1],v=id[i+1][r];
				for(int k=1;k<=MX;++k)
				{
					f[cur][k]+=f[u][k]*f[v][k-1]%MOD;
					Mod(f[cur][k]);
				}
			}
		}
	}
	for(int i=1;i<=MX;++i)
		f[cur][i]+=f[cur][i-1],Mod(f[cur][i]);
}
void Solve(int l,int r)
{
	if(r-l+1<=n+1)
	{
		for(int i=1;i<=tot;++i) f[i][0]=f[i][r-l+1];	
		return ;
	}
	ll P=1;
	for(int i=1;i<=n+1;++i)
		P=P*(r-l-i+1+MOD)%MOD;
	pre[n+2]=1;
	for(int i=n+1;i>=1;--i)
	{
		inv[i]=qpw(r-l-i+1+MOD,MOD-2)%MOD;
		pre[i]=pre[i+1]*inv[i]%MOD;
	}
	for(int k=1;k<=tot;++k)
	{
		ll res=0;
		int len=R[k]-L[k]+1;
		for(int i=1;i<=len+1;++i)
		{
			ll p=P*inv[i]%MOD*pre[len+2]%MOD,q=df[len+1-i]*fac[i-1]%MOD;
			res+=f[k][i]*p%MOD*q%MOD;
			Mod(res);
		}
		f[k][0]=res;
	}
}
int main()
{
	freopen("robot.in","r",stdin);
	freopen("robot.out","w",stdout);

	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d %d",&A[i],&B[i]);
	for(int i=1;i<=n;++i)
	{
		B[i]++;
		C[i]=A[i];
		C[i+n]=B[i];
	}
	sort(C+1,C+1+2*n);
	int siz=unique(C+1,C+1+2*n)-C-1;
	for(int i=1;i<=n;++i)
	{
		A[i]=lower_bound(C+1,C+1+siz,A[i])-C;
		B[i]=lower_bound(C+1,C+1+siz,B[i])-C;
	}
	fac[0]=df[0]=1;
	for(int i=1;i<=n+1;++i) fac[i]=fac[i-1]*i%MOD,df[i]=df[i-1]*(MOD-i)%MOD;
	fac[n+1]=qpw(fac[n+1],MOD-2);df[n+1]=qpw(df[n+1],MOD-2);
	for(int i=n;i>=0;--i) fac[i]=fac[i+1]*(i+1)%MOD,df[i]=df[i+1]*(MOD-i-1)%MOD;
	init(1,n);
	int Node=tot;
	for(pair<int,int> v:vec) id[v.first][v.second]=++Node;
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=n;++j)
		{
			if(id[i][j])
			{
				L[id[i][j]]=i;
				R[id[i][j]]=j;
			}
		}
	}
	for(int i=1;i<siz;++i)
	{
		T=i;
		MX=min(n+1ll,C[i+1]-C[i]);memset(vis,0,sizeof vis);
		for(int j=1;j<=n;++j) for(int k=j;k<=n;++k) if(id[j][k]) dfs(j,k);
		Solve(C[i],C[i+1]-1);
		for(int j=1;j<=Node;++j)for(int k=1;k<=MX;++k) f[j][k]=0;
	}
	printf("%lld\n",f[id[1][n]][0]);
	return 0;
}

前 60 分

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MOD = 1e9+7;
const int MAXN = 305;
int A[MAXN],B[MAXN],n;
namespace pt20
{
	int C[MAXN],Ans,st[MAXN],L[MAXN],R[MAXN],top;
	bool check()
	{
		for(int i=1;i<=n;++i) L[i]=0,R[i]=n+1;
		top=0;
		for(int i=1;i<=n;++i)
		{
			while(top&&C[i]>=C[st[top]]) --top;
			if(top) L[i]=st[top];
			st[++top]=i;
		}
		top=0;
		for(int i=n;i>=1;--i)
		{
			while(top&&C[i]>C[st[top]]) --top;
			if(top) R[i]=st[top];
			st[++top]=i;
		}
		for(int i=1;i<=n;++i)
			if(abs((R[i]-i)-(i-L[i]))>2) return false;
		return true;
	}
	void dfs(int p)
	{
		if(p>n)
		{
			if(check()) ++Ans;
			return ;
		}
		for(int i=A[p];i<=B[p];++i)
		{
			C[p]=i;
			dfs(p+1);
		}
	}
	void Solve()
	{
		Ans=0;
		dfs(1);
		printf("%d\n",Ans);
	}
}
namespace pt50
{
	int tot,id[305][305],m;
	ll f[3005][10005];
	void dfs(int l,int r)
	{
		if(id[l][r]) return ;
		int cur=++tot;id[l][r]=cur;
		if(l>r) f[cur][0]=1;
		else
		{
			for(int i=l;i<=r;++i)
			{
				if(abs(2*i-l-r)<=2)
				{
					dfs(l,i-1);dfs(i+1,r);
					for(int k=A[i];k<=B[i];++k)
					{
						f[cur][k]+=(f[id[l][i-1]][k]*f[id[i+1][r]][k-1])%MOD;
						f[cur][k]%=MOD;
					}
				}
			}
		}
		for(int i=1;i<=10000;++i)
			f[cur][i]=(f[cur][i-1]+f[cur][i])%MOD;
	}
	void Solve(int mx)
	{
		m=mx;
		dfs(1,n);
		printf("%lld\n",f[id[1][n]][m]);
	}
	ll Get_ans(int mx)
	{
		tot=0;memset(f,0,sizeof f);memset(id,0,sizeof id);m=mx;
		for(int i=1;i<=n;++i) B[i]=mx;
		dfs(1,n);
		return f[id[1][n]][m];
	}
}
namespace pt60
{
	ll qpw(ll x,ll b)
	{
		ll r=1;
		for(;b;b>>=1,x=x*x%MOD) if(b&1) r=r*x%MOD;
		return r;
	}
	void Solve()
	{
		ll Ans=0,tmp=0,X=1e9;
		for(int i=1;i<=100;++i)
		{
			tmp=pt50::Get_ans(i)%MOD;
			ll val=1;
			for(int j=1;j<=100;++j)
				if(i!=j) val=val*(X-j+MOD)%MOD*qpw(i-j+MOD,MOD-2)%MOD;
			Ans=(Ans+val*tmp%MOD)%MOD;
		}
		printf("%lld\n",Ans);
	}
}
int main()
{
	freopen("robot.in","r",stdin);
	freopen("robot.out","w",stdout);

	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d %d",&A[i],&B[i]);
	int mx=0;
	for(int i=1;i<=n;++i) mx=max(mx,B[i]);
	if(n<=7) pt20::Solve();
	else if(mx<=10000) pt50::Solve(mx);
	else pt60::Solve();
	return 0;
}
posted @ 2022-04-25 21:31  夜空之星  阅读(45)  评论(1编辑  收藏  举报