NOIP2020 T4微信步数

题目描述

有一个(k)维空间,以及一个行走方案,求从空间中每个点出发按行走方案行走走出范围的步数之和。

题解

这题考试时没有细想,只打了暴力,时间都拿去肝T3了。

难度其实也跟平时模拟赛做的难题差不多,但的的确确是超出了自己的能力范围。

首先考虑将步数之和转化为在走了当前步数时,还有多少个点没有走出范围,然后以此统计答案。

容易发现,对于每一层而言,都是最两侧的点最先走出去。并且可以进一步发现,从第二轮开始,每轮走出去的点数都是相同的。

于是可以考虑先处理出第一轮的答案,然后计算出从第二轮开始每一轮走出去的点数。

于是不妨考虑先枚举当前是在某一轮的第(i)步,然后考虑当前这一步会在第几轮让所有的点都走出范围。于是会发现对于后半部分会是一个多项式的部分,可以考虑设(f_{i,j})表示当前乘了(i)次,自变量也就是轮数的指数是(j)项的系数,简单多项式乘法即可。

对于最后如何利用这个求答案的部分:发现当(kge3)时,轮数最多只有(1000000),于是可以预处理;当(kle3)时,可以直接用公式算。

参考了:https://www.luogu.com.cn/blog/wcsb/solution-p7116

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 500010
#define mo 1000000007
#define ll long long
#define two 500000004
#define six 166666668
#define four 250000002
#pragma GCC optimize(2)
#define K 11
using namespace std;
ll n,k,ans,i,j,p,T,w[K],f[K][K],sum[N*2][K],mi[N*2][K],c,d,e[K],l[N][K],r[N][K],temp,a[K],b[K],bzans,mx;
ll read(){
	ll x=0,f=1;
	char ch=getchar();
	while (ch<'0'||ch>'9'){
		if (ch=='-') f=-1;
		ch=getchar();
	}
	while (ch>='0'&&ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
ll solve(ll T,ll k){
	if (k>3) return sum[T][k];
	if (k==0) return T+1;
	if (k==1) return T*(T+1)%mo*two%mo;
	if (k==2) return T*(T+1)%mo*(2*T+1)%mo*six%mo;
	return T*T%mo*(T+1)%mo*(T+1)%mo*four%mo;
}
int main(){
	freopen("walk.in","r",stdin);
	freopen("walk.out","w",stdout);
	n=read();k=read();
	for (i=1;i<=k;i++) w[i]=read(),mx=max(w[i],mx);
	if (k>3){
		for (i=0;i<=mx;i++){
			mi[i][0]=1;
			for (j=1;j<=k;j++) mi[i][j]=mi[i][j-1]*i%mo;
		} 
		for (i=0;i<=k;i++)
			for (j=0;j<=mx;j++) sum[j][i]=(sum[j-1][i]+mi[j][i])%mo;
	}
	for (i=1;i<=n;i++){
		c=read();d=read();
		e[c]+=d;
		for (j=1;j<=k;j++){
			l[i][j]=l[i-1][j];
			r[i][j]=r[i-1][j];
		}
		l[i][c]=min(l[i][c],e[c]);
		r[i][c]=max(r[i][c],e[c]);
	}
	for (i=1;i<=k;i++)
		if (e[i]!=0||l[n][i]<-w[i]||r[n][i]>w[i]) bzans=1;
	if (!bzans){
		printf("-1
");
		return 0;
	}
	for (i=0;i<=n;i++){
		temp=1;
		for (j=1;j<=k;j++) temp=temp*max(0ll,(w[j]-(r[i][j]-l[i][j])))%mo;
		ans=(ans+temp)%mo;
	}
	for (i=1;i<=k;i++) a[i]=w[i]-(r[n][i]-l[n][i]);
	for (i=1;i<=n;i++)
		for (j=1;j<=k;j++)
			l[i][j]=min(0ll,l[i][j]+e[j]-l[n][j]),r[i][j]=max(0ll,r[i][j]+e[j]-r[n][j]);
	for (i=1;i<=k;i++) b[i]=r[n][i]-l[n][i];
	for (i=1;i<=n;i++){
		T=1e9;
		for (p=1;p<=k;p++) if (b[p]) T=min(T,(a[p]-(r[i][p]-l[i][p]))/b[p]);
		if (T<1) break;
		f[0][0]=1;
		for (j=1;j<=k;j++)
			for (p=0;p<=k;p++){
				f[j][p]=f[j-1][p]*(a[j]-(r[i][j]-l[i][j]))%mo;
				if (p) f[j][p]=(f[j][p]+f[j-1][p-1]*(-b[j]))%mo;
			}
		for (p=0;p<=k;p++)
			ans=(ans+f[k][p]*solve(T,p))%mo;
	}
	printf("%lld
",(ans+mo)%mo);
	return 0;
}
原文地址:https://www.cnblogs.com/Mohogany/p/14151952.html