题目描述
有一个(k)维空间,以及一个行走方案,求从空间中每个点出发按行走方案行走走出范围的步数之和。
题解
这题考试时没有细想,只打了暴力,时间都拿去肝T3了。
难度其实也跟平时模拟赛做的难题差不多,但的的确确是超出了自己的能力范围。
首先考虑将步数之和转化为在走了当前步数时,还有多少个点没有走出范围,然后以此统计答案。
容易发现,对于每一层而言,都是最两侧的点最先走出去。并且可以进一步发现,从第二轮开始,每轮走出去的点数都是相同的。
于是可以考虑先处理出第一轮的答案,然后计算出从第二轮开始每一轮走出去的点数。
于是不妨考虑先枚举当前是在某一轮的第(i)步,然后考虑当前这一步会在第几轮让所有的点都走出范围。于是会发现对于后半部分会是一个多项式的部分,可以考虑设(f_{i,j})表示当前乘了(i)次,自变量也就是轮数的指数是(j)项的系数,简单多项式乘法即可。
对于最后如何利用这个求答案的部分:发现当(kge3)时,轮数最多只有(1000000),于是可以预处理;当(kle3)时,可以直接用公式算。
参考了:https://www.luogu.com.cn/blog/wcsb/solution-p7116
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 500010
#define mo 1000000007
#define ll long long
#define two 500000004
#define six 166666668
#define four 250000002
#pragma GCC optimize(2)
#define K 11
using namespace std;
ll n,k,ans,i,j,p,T,w[K],f[K][K],sum[N*2][K],mi[N*2][K],c,d,e[K],l[N][K],r[N][K],temp,a[K],b[K],bzans,mx;
ll read(){
ll x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
ll solve(ll T,ll k){
if (k>3) return sum[T][k];
if (k==0) return T+1;
if (k==1) return T*(T+1)%mo*two%mo;
if (k==2) return T*(T+1)%mo*(2*T+1)%mo*six%mo;
return T*T%mo*(T+1)%mo*(T+1)%mo*four%mo;
}
int main(){
freopen("walk.in","r",stdin);
freopen("walk.out","w",stdout);
n=read();k=read();
for (i=1;i<=k;i++) w[i]=read(),mx=max(w[i],mx);
if (k>3){
for (i=0;i<=mx;i++){
mi[i][0]=1;
for (j=1;j<=k;j++) mi[i][j]=mi[i][j-1]*i%mo;
}
for (i=0;i<=k;i++)
for (j=0;j<=mx;j++) sum[j][i]=(sum[j-1][i]+mi[j][i])%mo;
}
for (i=1;i<=n;i++){
c=read();d=read();
e[c]+=d;
for (j=1;j<=k;j++){
l[i][j]=l[i-1][j];
r[i][j]=r[i-1][j];
}
l[i][c]=min(l[i][c],e[c]);
r[i][c]=max(r[i][c],e[c]);
}
for (i=1;i<=k;i++)
if (e[i]!=0||l[n][i]<-w[i]||r[n][i]>w[i]) bzans=1;
if (!bzans){
printf("-1
");
return 0;
}
for (i=0;i<=n;i++){
temp=1;
for (j=1;j<=k;j++) temp=temp*max(0ll,(w[j]-(r[i][j]-l[i][j])))%mo;
ans=(ans+temp)%mo;
}
for (i=1;i<=k;i++) a[i]=w[i]-(r[n][i]-l[n][i]);
for (i=1;i<=n;i++)
for (j=1;j<=k;j++)
l[i][j]=min(0ll,l[i][j]+e[j]-l[n][j]),r[i][j]=max(0ll,r[i][j]+e[j]-r[n][j]);
for (i=1;i<=k;i++) b[i]=r[n][i]-l[n][i];
for (i=1;i<=n;i++){
T=1e9;
for (p=1;p<=k;p++) if (b[p]) T=min(T,(a[p]-(r[i][p]-l[i][p]))/b[p]);
if (T<1) break;
f[0][0]=1;
for (j=1;j<=k;j++)
for (p=0;p<=k;p++){
f[j][p]=f[j-1][p]*(a[j]-(r[i][j]-l[i][j]))%mo;
if (p) f[j][p]=(f[j][p]+f[j-1][p-1]*(-b[j]))%mo;
}
for (p=0;p<=k;p++)
ans=(ans+f[k][p]*solve(T,p))%mo;
}
printf("%lld
",(ans+mo)%mo);
return 0;
}