题目大意: 有一个 k k k 维空间,你要从每一个位置出发走一条循环路线,直到走出边界为止,求走过的总步数。
题解
转化一下,每天走过的总步数,等于每个时刻能走的天数之和。
将 n n n 步看成一轮,那么每轮内在一维上走过的一定是个区间。
设 一轮内,走了第 i i i 步后,在第 j j j 维走过的这个区间为 [ x j + l i , j , x j + r i , j ] [x_j+l_{i,j},x_j+r_{i,j}] [xj+li,j,xj+ri,j],那么在走到第 i i i 步还没有走出边界的点,就需要满足 1 − l i , j ≤ x j ≤ w j − r i , j 1-l_{i,j}\leq x_j\leq w_j-r_{i,j} 1−li,j≤xj≤wj−ri,j。
设 一轮后,第 j j j 维的位移为 d j d_j dj。除了第一轮和最后一轮,走过一轮后,第 j j j 维一定有恰好 d j d_j dj 个位置走出边界,那么第 2 + t ( t ≥ 0 ) 2+t(t\geq 0) 2+t(t≥0) 轮的第 i i i 步时,第 j j j 维能用的位置就有 w j − max ( r n , j , r i , j + d j ) + m i n ( l n , j , l i , j + d j ) − ∣ d j ∣ × t w_j-\max(r_{n,j},r_{i,j}+d_j)+min(l_{n,j},l_{i,j}+d_j)-|d_j|\times t wj−max(rn,j,ri,j+dj)+min(ln,j,li,j+dj)−∣dj∣×t 个。
乘起来,就得到了第 t t t 轮,第 i i i 步时还没有走出边界的起点个数。发现这是个关于 t t t 的 k k k 次多项式,记为 f i ( t ) = ∑ j = 0 k a j t j f_i(t)=\sum_{j=0}^k a_jt^j fi(t)=∑j=0kajtj,不难得出 t t t 的上界,记为 t m a x t_{max} tmax,那么贡献就是 ∑ t = 0 t m a x f i ( t ) = ∑ t = 0 t m a x ∑ j = 0 k a j t j = ∑ j = 0 k a j ∑ t = 0 t m a x t j \sum_{t=0}^{t_{max}}f_i(t)=\sum_{t=0}^{t_{max}}\sum_{j=0}^ka_jt^j=\sum_{j=0}^ka_j\sum_{t=0}^{t_{max}}t^j ∑t=0tmaxfi(t)=∑t=0tmax∑j=0kajtj=∑j=0kaj∑t=0tmaxtj。
后面是个自然数幂和,用拉格朗日插值搞搞就行。那么每次需要 k 2 k^2 k2 暴力卷出 f i ( t ) f_i(t) fi(t),时间复杂度就是 O ( n k 2 ) O(nk^2) O(nk2)。
以及第 1 1 1 轮和第 t m a x + 1 t_{max}+1 tmax+1 轮要单独计算,用那个将每一维可用起点数乘起来的做法算即可。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define mod 1000000007
int n,k,w[11],ans=0;
int d[11];
int l[500010][11],r[500010][11];
void add(int &x,int y){
x=(x+y>=mod?x+y-mod:x+y);}
void dec(int &x,int y){
x=(x-y<0?x-y+mod:x-y);}
struct Poly{
int a[11],t;
Poly(){
t=0;memset(a,0,sizeof(a));}
void clear(){
t=0;memset(a,0,sizeof(a));}
void operator *=(Poly &B){
Poly re;re.t=t+B.t;
for(int i=0;i<=t;i++)
for(int j=0;j<=B.t;j++)
add(re.a[i+j],1ll*a[i]*B.a[j]%mod);
*this=re;
}
}s[11];
int t_max=1e9;
int calc_round_1(){
//暴力求解第一轮
int re=0;
for(int i=1;i<=n;i++){
int prod=1;
for(int j=1;j<=k;j++)
if(w[j]-r[i][j]+l[i][j]>0)
prod=1ll*prod*(w[j]-r[i][j]+l[i][j])%mod;
else {
prod=0;break;}
add(re,prod);
}
return re;
}
int calc_round_t_max_and_1(){
//暴力求解最后一轮
int re=0;
for(int i=1;i<=n;i++){
int prod=1;
for(int j=1;j<=k;j++){
int p=w[j]-max(r[n][j],r[i][j]+d[j])+min(l[n][j],l[i][j]+d[j])-(t_max+1)*abs(d[j]);
if(p>0)prod=1ll*prod*p%mod;
else {
prod=0;break;}
}
add(re,prod);
}
return re;
}
int ksm(int x,int y){
int re=1;for(;(y&1?re=1ll*re*x%mod:0),y;y>>=1,x=1ll*x*x%mod);return re;}
struct Lagrange{
//自然数幂和板子
int fac[20],inv_fac[20];
Lagrange(){
}
void init(){
fac[0]=inv_fac[0]=1;
for(int i=1;i<=15;i++)fac[i]=1ll*fac[i-1]*i%mod;
inv_fac[15]=ksm(fac[15],mod-2);
for(int i=14;i>=1;i--)inv_fac[i]=1ll*inv_fac[i+1]*(i+1)%mod;
}
int pre[20],suf[20];
int calc(int k,int x){
if(!k)return x+1;
int re=0,sum=0;
if(x<=k+2){
for(int i=0;i<=x;i++)add(re,ksm(i,k));
return re;
}
pre[0]=1;for(int i=1;i<=k+2;i++)pre[i]=1ll*pre[i-1]*(x-i)%mod;
suf[k+3]=1;for(int i=k+2;i>=1;i--)suf[i]=1ll*suf[i+1]*(x-i)%mod;
for(int i=1;i<=k+2;i++){
add(sum,ksm(i,k));
(k+2-i&1?dec:add)(re,1ll*sum*pre[i-1]%mod*suf[i+1]%mod
*inv_fac[i-1]%mod*inv_fac[k+2-i]%mod);
}
return re;
}
}Lag;
int cd[20];
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;
for(int i=1,x,y;i<=n;i++){
scanf("%d %d",&x,&y);
d[x]+=y;
for(int j=1;j<=k;j++)
l[i][j]=min(l[i-1][j],d[j]),
r[i][j]=max(r[i-1][j],d[j]);
}
bool tf=false;//判无解
for(int i=1;i<=k;i++)
if(l[n][i]+r[n][i]>=w[i]||d[i]!=0)tf=true;
if(!tf)return puts("-1"),0;
for(int i=1;i<=k;i++)//求t_max
if(w[i]-r[n][i]+l[n][i]<=0){
t_max=-2;break;}
else if(d[i]!=0)t_max=min(t_max,(w[i]-r[n][i]+l[n][i])/abs(d[i])-1);
add(ans,calc_round_1());
if(t_max>-2)add(ans,calc_round_t_max_and_1());
if(t_max>=0){
Lag.init();//预处理自然数幂和
for(int i=0;i<=k;i++)
cd[i]=Lag.calc(i,t_max);
for(int i=1;i<=n;i++){
for(int j=1;j<=k;j++){
s[j].clear();//计算出所有多项式,暴力乘起来
s[j].t=d[j]!=0;
s[j].a[0]=w[j]-max(r[n][j],r[i][j]+d[j])+min(l[n][j],l[i][j]+d[j]);
s[j].a[1]=(mod-abs(d[j]))%mod;
if(j>1)s[j]*=s[j-1];
}
for(int j=0;j<=k;j++)
add(ans,1ll*s[k].a[j]*cd[j]%mod);
}
}
printf("%d",ans);
}