• NOIP 2020 T4 微信步数


    description

    solution

    咕咕了这么久,终于来填坑了。。。

    首先(-1) 的情况是容易判断的,这里不再赘述。

    根据“交换和式”的思想,我们需要将对于每个起点分别求路径长度最后求和转化为求每一时刻未走出边界的起点个数再求和(这里假设一单位时间走一步)。

    每个维度都是相对独立的。假如在某时刻第(i) 维只有([l_i,r_i]) 的起点不会走出边界,那么该时刻对答案的贡献就是(prod_limits {i=1}^k(r_i-l_i+1)) 。而对于第(i) 维,倘若从初始到某时刻的行走范围为([l_i,r_i]) (初始位置为0),那么只有([1,-l_i])([w_i-r_i+1,w_i]) 这些起点(共(r_i-l_i) 个)会走出边界(如果(r_i-l_i=w_i) 则所有点都会走出边界,直接输出答案)。根据上述方法可直接进行模拟,但复杂度仍然不可承受。

    不过注意到只有第一轮较为特殊,从第二轮开始开始有一定的规律性,例如第(i) 轮第(j) 步新走出边界的起点数当(ige 2) 时都是不会再改变的。于是我们对于第一轮以之前的方法计算,对于第二轮及以后,考虑对于第(j) 维我们设第一轮后剩下(a_j) 个起点,每轮结束后新走出边界起点数(b_j) 以及第(i) 步新走出边界的起点数(f_{j,i}) 。这些量都是容易求出的。那么我们最终要求的是

    [ans=sum_{i=1}^nsum_{t=0}^{T}prod_{j=1}^k(a_j-tb_j-f_{j,i}) ]

    其中(T=minlimits_{j=1}^klfloorfrac{a_j-f_{j,i}}{b_j} floor) 。最外层(i) 枚举最后一轮走了(i) 步,(t+2) 表示最后一轮是哪一轮,(a_j-tb_j-f_{j,i}) 则表示这一维未走出边界的起点个数。

    (f(t)=prod_{j=1}^k(a_j-tb_j-f_{j,i})) ,容易发现(f(t)) 是一个不超过(k) 次的多项式,可以用拉格朗日插值求出其各项系数(不过似乎暴力乘也可以)。考虑(f(t)=sum_{i=0}^kc_it^i) ,于是有

    [egin{aligned} ans&=sum_{i=1}^nsum_{t=0}^Tsum_{p=0}^kc_pt^p\ &=sum_{i=1}^nsum_{p=0}^kc_psum_{t=0}^Tt^p end{aligned} ]

    后面部分是一个自然数幂和,也可以通过插值(mathcal O(k)) 求出(或者通过公式+预处理),因此总复杂度为(mathcal O(nk^2))

    code

    #include<bits/stdc++.h>
    using namespace std;
    const int N=5e5+5,M=15,mod=1e9+7,iv6=166666668;
    inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
    inline void inc(int&x,int y){x=add(x,y);}
    inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
    inline int qpow(int x,int y,int res=1)
    {
    	for(;y;y>>=1,x=1ll*x*x%mod)
    		(y&1)&&(res=1ll*res*x%mod);
    	return res;
    }
    int n,k,w[M],c[N],d[N],l[N][M],r[N][M],pos[M],ans,mx;
    int a[M],b[M],f[M][N],t[M],p[M],g[M],h[M][M],ifac[N],pw[M][N<<1];
    inline void init()
    {
    	p[0]=1;
    	for(int z=0;z<=k;++z)
    	{
    		for(int i=k+1;i;--i)p[i]=dec(p[i-1],1ll*p[i]*z%mod);
    		p[0]=dec(0,1ll*p[0]*z%mod);
    	}
    	for(int j=0;j<=k;++j)h[0][j]=p[j+1];
    	for(int i=1;i<=k;++i)
    	{
    		h[i][0]=0;int iv=qpow(i,mod-2);
    		for(int j=1;j<=k;++j)
    			h[i][j]=1ll*dec(h[i][j-1],p[j])*iv%mod;
    	}
    	for(int i=0,o=1;i<=k;++i,o=1)
    	{
    		for(int j=0;j<=k;++j)
    			if(i^j)o=1ll*o*dec(i,j)%mod;
    		o=qpow(o,mod-2);
    		for(int j=0;j<=k;++j)h[i][j]=1ll*h[i][j]*o%mod;
    	}
    	int fac=1;for(int i=1;i<=k+1;++i)fac=1ll*fac*i%mod;
    	ifac[k+1]=qpow(fac,mod-2);
    	for(int i=k;~i;--i)ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
    	for(int i=4;i<=k;++i)
    		for(int j=1;j<=mx;++j)
    			pw[i][j]=add(pw[i][j-1],qpow(j,i));
    }
    inline void lagrange()
    {
    	fill(g,g+k+1,0);
    	for(int i=0;i<=k;++i)
    		for(int j=0;j<=k;++j)
    			inc(g[j],1ll*t[i]*h[i][j]%mod);
    }int suf[N],pre[N];
    inline int S(int o,int p)
    {
    	if(!o)return p+1;
    	if(o==1)return 1ll*p*(p+1)/2%mod;
    	if(o==2)return 1ll*p*(p+1)%mod*(p+p+1)%mod*iv6%mod;
    	if(o==3)return (1ll*p*(p+1)/2%mod)*(1ll*p*(p+1)/2%mod)%mod;
    	return pw[o][p];
    }
    int main()
    {
    	scanf("%d%d",&n,&k);ans=1;
    	for(int i=1;i<=k;++i)scanf("%d",&w[i]),ans=1ll*ans*w[i]%mod,mx=max(mx,w[i]);
    	for(int i=1;i<=n;++i)scanf("%d%d",c+i,d+i);
    	for(int i=1;i<=n;++i)
    	{
    		for(int j=1;j<=k;++j)
    			l[i][j]=l[i-1][j],r[i][j]=r[i-1][j];
    		pos[c[i]]+=d[i];
    		l[i][c[i]]=min(l[i][c[i]],pos[c[i]]);
    		r[i][c[i]]=max(r[i][c[i]],pos[c[i]]);
    		int res=1;
    		for(int j=1;j<=k;++j)
    			res=1ll*res*(w[j]-(r[i][j]-l[i][j]))%mod;
    		if(!res)return printf("%d
    ",ans),0;
    		inc(ans,res);
    	}
    	bool flag=0;
    	for(int i=1;i<=k;++i)if(pos[i]!=0){flag=1;break;}
    	if(!flag)return puts("-1"),0;
    	for(int i=1;i<=k;++i)
    	{
    		a[i]=w[i]-(r[n][i]-l[n][i]);
    		for(int j=1;j<=n;++j)
    		{
    			int dl=min(0,l[j][i]+pos[i]-l[n][i]);
    			int dr=max(0,r[j][i]+pos[i]-r[n][i]);
    			f[i][j]=dr-dl;
    		}
    		b[i]=f[i][n];
    	}init();
    	for(int i=1;i<=n;++i)
    	{
    		bool tp=0;
    		for(int j=1;j<=k;++j)if(a[j]<f[j][i]){tp=1;break;}
    		if(tp)continue;int T=mod;
    		for(int j=1;j<=k;++j)if(b[j])T=min(T,(a[j]-f[j][i])/b[j]);
    		for(int z=0,ret=1;z<=k&&z<=T;++z,ret=1)
    		{
    			for(int j=1;j<=k;++j)
    				ret=1ll*ret*(a[j]-z*b[j]-f[j][i])%mod;
    			t[z]=ret;
    		}
    		if(T<=k){for(int z=0;z<=T;++z)inc(ans,t[z]);continue;}
    		lagrange();
    		for(int j=0;j<=k;++j)inc(ans,1ll*g[j]*S(j,T)%mod);
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
    NO PAIN NO GAIN
  • 相关阅读:
    数据库表的主外键
    数据库条件查询及关系搭建
    MySQL数据库的基本认识与操作
    MySQL5.7安装详解及常见安装问题解决
    数据库介绍
    Sensor图像调试
    1.线性表
    发展建议
    typedef 与 #define 的区别
    音频处理
  • 原文地址:https://www.cnblogs.com/zmyzmy/p/15057429.html
Copyright © 2020-2023  润新知