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]\)
不過注意到只有第一輪較為特殊,從第二輪開始開始有一定的規律性,例如第\(i\) 輪第\(j\) 步新走出邊界的起點數當\(i\ge 2\) 時都是不會再改變的。於是我們對於第一輪以之前的方法計算,對於第二輪及以後,考慮對於第\(j\) 維我們設第一輪後剩下\(a_j\) 個起點,每輪結束後新走出邊界起點數\(b_j\) 以及第\(i\) 步新走出邊界的起點數\(f_{j,i}\)
其中\(T=\min\limits_{j=1}^k\lfloor\frac{a_j-f_{j,i}}{b_j}\rfloor\) 。最外層\(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\)
後面部分是一個自然數冪和,也可以通過插值\(\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\n",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\n",ans);
return 0;
}
NO PAIN NO GAIN