zoukankan      html  css  js  c++  java
  • NOIP 2020 题解

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

    T4

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

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

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

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

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

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

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

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

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

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

    (A_i - x imes 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
    ",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
    ",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
    ",ans);
    }
    
  • 相关阅读:
    UTF8转换为GB编码gb2312转换为utf-8
    localtime 和 localtime_r
    无损音频介绍
    bgr to rgb
    Farseer.Net
    为大家分享一个 Ajax Loading —— spin.js(转)
    HTML5-Ajax文件上传(转)
    Firefox火狐Flash插件卡死问题完美解决方法(转载)
    50 个最棒的 jQuery 日历插件,很齐全了!(转)
    linq to xml学习
  • 原文地址:https://www.cnblogs.com/youddjxd/p/14336615.html
Copyright © 2011-2022 走看看