zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    200行代码实现Mini ASP.NET Core
    使用Elastic APM监控你的.NET Core应用
    .NET西安社区「拥抱开源,又见 .NET:壹周年Party」活动简报
    西安7月21日「拥抱开源,又见.NET:壹周年Party」线下交流活动
    领域驱动设计(DDD)编码实践
    再谈领域驱动设计
    「拥抱开源, 又见 .NET」系列第三次线下活动简报
    西安活动 | 4月20日「拥抱开源,又见.NET :云时代 • 新契机」
    在Xunit中使用FsCheck
    rocketMq特性(features)
  • 原文地址:https://www.cnblogs.com/Mohogany/p/14151952.html
Copyright © 2011-2022 走看看