NOIP 2020 题解
考试结果就不说了...就只能蹭一等奖 自己实力真的不行
T4
首先,每个人活了多少天,相当于每一天活着的人数的和。
又发现在每一维上面仍然存活的范围肯定是连续的,那么总共活着的人数就是每一维活着的坐标个数的乘积。
之后,容易发现,在第一轮之后,每一轮的每一步的每一维的死亡的人数都是相同的。那么每一轮的每一维的总死亡人数也是相同的。
那么设第一轮后,每一维有\(A_i\)个人活着,之后的每一轮,每一维有\(B_i\)个人死去,
另外设在第一轮之后的每一轮中,第1~j步上第i维死的人有\(f_{i,j}\)个。
那么设一共k维,可以写出来第x+2轮中第j步的贡献:
\(\prod_{i=1}^{k} A_i - x \times B_i - f_{i,j}\)
设这一步最多能够出现T轮,总共的步数为n,则我们要算的最终答案就是
\(第一轮的贡献 + \sum_{i=1}^{n} \sum_{x=0}^{T} \prod_{i=1}^{k} A_i - x \times B_i - f_{i,j}\)
那么我们就要来算右边那条式子了。
当\(A_i - x \times 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\n",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\n",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\n",ans);
}