NOIP 2020 题解

考试结果就不说了...就只能蹭一等奖 自己实力真的不行

T4

首先,每个人活了多少天,相当于每一天活着的人数的和。

又发现在每一维上面仍然存活的范围肯定是连续的,那么总共活着的人数就是每一维活着的坐标个数的乘积。

之后,容易发现,在第一轮之后,每一轮的每一步的每一维的死亡的人数都是相同的。那么每一轮的每一维的总死亡人数也是相同的。

那么设第一轮后,每一维有\(A_i\)个人活着,之后的每一轮,每一维有\(B_i\)个人死去,

另外设在第一轮之后的每一轮中,第1~j步上第i维死的人有\(f_{i,j}\)个。

那么设一共k维,可以写出来第x+2轮中第j步的贡献:

\(\prod_{i=1}^{k} A_i - x \times B_i - f_{i,j}\)

设这一步最多能够出现T轮,总共的步数为n,则我们要算的最终答案就是

\(第一轮的贡献 + \sum_{i=1}^{n} \sum_{x=0}^{T} \prod_{i=1}^{k} A_i - x \times B_i - f_{i,j}\)

那么我们就要来算右边那条式子了。

\(A_i - x \times B_i - f_{i,j} > 0\)的时候,原多项式才有值,否则没有。

于是我们可以发现,\(x>\frac{A_i-f_{i,j}}{B_i}\),那么就有\(T=min(\frac{A_i-f_{i,j}}{B_i})_{j=1}^k\)

那么那条式子就可以算了。时间复杂度是\(O(nkT)\)

但是我们发现T会很大,就考虑优化。

发现右边的多项式是一个\(mx+n\)的形式,于是可以\(O(k^2)\)展开一下,成为一个k次多项式。

又发现,T显然最多只会有2个值,于是拉格朗日暴力插值一下,就能\(O(k^2)\)求出来每个多项式的值了(这里可以优化成\(O(k \log k)\)(参考CF622F),但是复杂度瓶颈不在这里,没啥意义)。

于是总的时间复杂度就是\(O(nk^2)\),可以通过此题。

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int mod=1e9+7;
int n,k;
int ans;
int w[15];
int c[500010];
int d[500010];
int a[11];
int e[11];
int l1[11][500010],r1[11][500010];
void firstround(){
	for(int i=1;i<=n;++i){
		int cc=c[i],dd=d[i];
		e[c[i]]=e[c[i]]+d[i];
		l1[c[i]][i]=min(l1[c[i]][i-1],e[c[i]]);
		r1[c[i]][i]=max(r1[c[i]][i-1],e[c[i]]);
		int tmp=1;
		tmp=((tmp*((w[c[i]]-r1[c[i]][i]+l1[c[i]][i])%mod))%mod+mod)%mod;
		for(int j=1;j<=k;++j){
			if(j==c[i])continue;
			l1[j][i]=l1[j][i-1];
			r1[j][i]=r1[j][i-1];
			tmp=((tmp*((w[j]-r1[j][i]+l1[j][i])%mod))%mod+mod)%mod;
		}
		if(!tmp){
			printf("%lld\n",ans);
			exit(0);
		}
		ans=(ans+tmp)%mod;
	}
	bool mk=false;
	for(int i=1;i<=k;++i){
		if(e[i]!=0)mk=true;
	}
	if(!mk){
		puts("-1");
		exit(0);
	}
	for(int i=1;i<=k;++i){
		a[i]=w[i]-r1[i][n]+l1[i][n];
	}
}
int b[11];
int l2[11][500010],r2[11][500010];
int f[11][500010];
void secondround(){
	int tmp1=ans;
	for(int i=1;i<=n;++i){
		int tmp=1;
		l2[c[i]][i]=min(l2[c[i]][i-1],min(l1[c[i]][i]+e[c[i]]-l1[c[i]][n],0ll));
		r2[c[i]][i]=max(r2[c[i]][i-1],max(r1[c[i]][i]+e[c[i]]-r1[c[i]][n],0ll));
		f[c[i]][i]=r2[c[i]][i]-l2[c[i]][i];
		if(f[c[i]][i]>=a[c[i]]){
			printf("%lld\n",tmp1);
			exit(0);
		}
		for(int j=1;j<=k;++j){
			if(c[i]!=j){
				f[j][i]=f[j][i-1];
				l2[j][i]=l2[j][i-1];
				r2[j][i]=r2[j][i-1];
			}
			tmp=(tmp*(a[j]-f[j][i])%mod)%mod;
		}
		tmp1=(tmp1+tmp)%mod;
	}
	for(int i=1;i<=k;++i){
		b[i]=f[i][n];
	}
}
struct data{
	int m;
	int n;
}t[11];
void solve(int jj,int *now){
	for(int i=1;i<=k;++i){
		t[i].m=(-b[i]%mod+mod)%mod;t[i].n=((a[i]-f[i][jj])%mod+mod)%mod;
	}
	now[0]=t[1].n,now[1]=t[1].m;
	int tmp1[11];
	int tmp2[11];
	tmp2[0]=0;
	for(int i=2;i<=k;++i){
		for(int j=0;j<=k;++j){
			tmp2[j+1]=now[j]*t[i].m%mod;
			tmp1[j]=now[j]*t[i].n%mod;
		}
		for(int j=0;j<=k;++j){
			now[j]=(tmp1[j]+tmp2[j])%mod;
		}
	}
}
int p[11];
int xk[11][51];
void pre_xk(){
	xk[0][0]=1;
	for(int j=1;j<=50;++j){
		int now=1;
		xk[0][j]=(xk[0][j-1]+1)%mod;
		for(int i=1;i<=k;++i){
			now=(now*j)%mod;
			xk[i][j]=(xk[i][j-1]+now)%mod;
		}
	}
}
void extgcd(int a,int b,int &d,int &x,int &y){
    if(!b){ 
		d=a;
		x=1,y=0;
		return;
	} 
	extgcd(b,a%b,d,y,x);
	y-=x*(a/b);
}
int inverse(int a){
    int d,x,y;
    extgcd(a,mod,d,x,y);
    return d==1?(x+mod)%mod:-1;
}
int xx[20],yy[20];
int cz[20][2];
int chazhi(int k,int t){
	if(t<=50)return xk[k][t];
	for(int i=1;i<=k+2;++i){
		xx[i-1]=i;
		yy[i-1]=xk[k][i];
	}	
	int ret=0;
	int tmpx,tmpy,tmp;
	for(int i=0;i<=k+1;++i){
		tmpx=1,tmpy=1;
		for(int j=0;j<=k+1;++j){
			if(i==j)continue;
			tmpx=((tmpx*(t-xx[j])%mod)%mod+mod)%mod;
			tmpy=((tmpy*(xx[i]-xx[j])%mod)%mod+mod)%mod;
		}
		tmp=(tmpx*inverse(tmpy))%mod;
		tmp=(tmp*yy[i])%mod;
		ret=(ret+tmp)%mod;
	}
	return ret;
}
int tt[500010];
signed main(){
	scanf("%lld%lld",&n,&k);
	int tmp=1;
	for(int i=1;i<=k;++i){
		scanf("%lld",&w[i]);
		tmp=tmp*w[i]%mod;
	}
	ans=tmp;
	for(int i=1;i<=n;++i){
		scanf("%lld%lld",&c[i],&d[i]);
	}
	firstround();
	secondround();
	pre_xk();
	int lst;
	int T1=19198e10,T2=-19198e10;
	for(int i=1;i<=n;++i){
		tt[i]=19198e10;
		for(int j=1;j<=k;++j){
			if(b[j]!=0)tt[i]=min(tt[i],(a[j]-f[j][i])/b[j]);
		}
		T1=min(T1,tt[i]),T2=max(T2,tt[i]);
	}
	for(int i=0;i<=k;++i){
		cz[i][0]=chazhi(i,T1);
		cz[i][1]=chazhi(i,T2);
	}
	for(int i=1;i<=n;++i){
		memset(p,0,sizeof(p));
		solve(i,p);
		for(int j=0;j<=k;++j){
			ans=(ans+(p[j]*cz[j][tt[i]-T1])%mod)%mod;
		}
	}
	printf("%lld\n",ans);
}
posted @ 2021-01-27 19:39  FakeDragon  阅读(139)  评论(0编辑  收藏  举报