• 洛谷 P7116


    洛谷题面传送门

    我竟然独立切掉了这道题!incredible!

    纪念我逝去的一上午(NOIP 总时长 4.5h,这题做了我整整 4.5h)

    首先讲一下现场我想的 80 分的做法,虽然最后挂成了 65 分,但大概率是被卡常了(

    注意到虽然点数高达 (prodlimits_{i=1}^kw_i),但每一维我们都可以单独考虑,具体来说,我们设 (tim_{i,j}) 表示只考虑 (c_k=i)(k),当前第 (i) 维坐标是 (j),最少需要多少步才能离开场地(tim_{i,j}) 显然 xjb 分类讨论就能求出。那么由于每一维的独立性,对于一个坐标 ((x_1,x_2,cdots,x_k)),它所需要的离开场地的最小时间就是对应每一维所需时间取 (min),即 (minlimits_{i=1}^ktim_{i,x_i}),也就是说我们要求的东西就是 (sumlimits_{x_ile w_i}minlimits_{i=1}^ktim_{i,x_i}),我们考虑将 (tim_{i,j}) 全部揉在一起从大到小排序并枚举 (minlimits_{i=1}^ktim_{i,x_i}=tim_{x,y}),那么此时合法的坐标数目就是 (prodlimits_{j e x}cnt_j),其中 (cnt_j=sumlimits_{k=1}^{w_j}[tim_{j,k}>tim_{x,y}]),这个值可以通过预处理逆元在枚举的过程中 (mathcal O(1)) 求得。那么,加上排序的复杂度,总复杂度大概是 (nklog nk)然鹅这个复杂度不开 O2 是过不去的,有我现场写的程序为证。因此考虑加点小小的剪枝,注意到 (tim_{i,j}) 随着 (j) 的增大是一个凸函数,因此咱考虑找到该函数的峰点,然后将两部分归并起来即可在 (mathcal O(w_i)) 的时间内将某个 (tim_{i}) 从大到小排序,然后再将所有 (tim_i) 再归并起来即可。然鹅有一个让人非常哭笑不得的细节,就是在对全部 (k) 个数组归并时,找最小值用 priority_queue,时间复杂度 (mathcal O(nklog k)) 反而 TLE,改成暴力 (mathcal O(k)) 找反而就过了,大概是常数的问题吧。

    附:80 分的代码:

    const int MAXN=5e5;
    const int MAXK=10;
    const int MOD=1e9+7;
    int n,k,c[MAXN+5],d[MAXN+5],w[MAXK+2];
    namespace sub1{
    	bool check(){
    		int flg=1;
    		for(int i=1;i<=k;i++) flg&=(w[i]<=1e6);
    		return flg;
    	}
    	const int MAXW=1e6;
    	const ll INF=0x3f3f3f3f3f3f3f3fll;
    	ll tim[MAXK+2][MAXW+5];
    	int lft[MAXW+5],rit[MAXW+5];
    	void calc(int x){
    		memset(lft,0,sizeof(lft));memset(rit,0,sizeof(rit));
    		int mn=0,mx=0,cur=0;
    		for(int i=1;i<=n;i++) if(c[i]==x) cur+=d[i];
    		if(cur<0){
    			for(int i=1;i<=n;i++) if(c[i]==x) d[i]=-d[i];
    		} cur=0;
    		for(int i=1;i<=n;i++) if(c[i]==x){
    			cur+=d[i];
    			if(cur>mx) rit[cur]=i,mx=cur;
    			if(cur<mn) lft[-cur]=i,mn=cur;
    		}
    		for(int i=1;i<=w[x];i++){
    			tim[x][i]=INF;
    			if(i+mn<=0) chkmin(tim[x][i],(ll)lft[i]);
    			if(i+mx>w[x]) chkmin(tim[x][i],(ll)rit[w[x]+1-i]);
    			if(cur){
    				int bound=w[x]-mx+1;
    				int tt=max((bound-i+cur-1)/cur,0);
    				chkmin(tim[x][i],1ll*tt*n+rit[w[x]+1-(i+tt*cur)]);
    			}
    		}
    	} ll A[MAXW+5],B[MAXW+5];
    	int inv[MAXW+5];
    	void mergesort(int x){
    		int ps=0,c1=0,c2=0;
    		for(int i=1;i<=w[x];i++) if(tim[x][i]>tim[x][i+1]){ps=i;break;}
    		for(int i=ps;~i;i--) A[++c1]=tim[x][i];A[c1+1]=0;
    		for(int i=ps+1;i<=w[x];i++) B[++c2]=tim[x][i];B[c2+1]=0;
    		for(int i=1,p1=1,p2=1;i<=w[x];i++){
    			if(A[p1]>B[p2]) tim[x][i]=A[p1++];
    			else tim[x][i]=B[p2++];
    		}
    	}
    	int cnt[MAXK+5];
    	void solve(){
    		for(int i=1;i<=k;i++) calc(i);
    		for(int i=1;i<=k;i++) mergesort(i);
    		for(int i=(inv[0]=inv[1]=1)+1;i<=MAXW;i++)
    			inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
    		int sm=0;for(int i=1;i<=k;i++) sm+=w[i];
    		bool flg=1;
    		for(int i=1;i<=k;i++) flg&=(tim[i][1]==INF);
    		if(flg) return puts("-1"),void();
    		int res=1,cnt0=k,ans=0;
    		for(int i=1;i<=sm;i++){
    			int x=0;
    			for(int j=1;j<=k;j++) if(tim[j][cnt[j]+1]>tim[x][cnt[x]+1]) x=j;
    			if(!cnt[x]) cnt0--;
    			else res=1ll*res*inv[cnt[x]]%MOD*(cnt[x]+1)%MOD;
    			++cnt[x];
    			if(!cnt0&&tim[x][cnt[x]]) ans=(ans+tim[x][cnt[x]]%MOD*res%MOD*inv[cnt[x]])%MOD;
    		} printf("%d
    ",ans);
    	}
    }
    int main(){
    	freopen("walk.in","r",stdin);
    	freopen("walk.out","w",stdout);
    	scanf("%d%d",&n,&k);
    	for(int i=1;i<=k;i++) scanf("%d",&w[i]);
    	for(int i=1;i<=n;i++) scanf("%d%d",&c[i],&d[i]);
    	if(sub1::check()) sub1::solve();
    	return 0;
    }
    

    接下来考虑正解,也就是这个脑子不太好使的人今早灵机一动想出来的做法。

    我们考虑预处理出这样几个量:

    • (x_i):在一整个长度为 (n) 周期中,如果我们将起点视为源点,那么在一个周期中第 (i) 维坐标的最小值是多少。
    • (y_i):在一整个长度为 (n) 周期中,如果我们将起点视为源点,那么在一个周期中第 (i) 维坐标的最大值是多少。
    • (t_i):在一整个长度为 (n) 周期中,如果我们将起点视为源点,那么在一个周期结束后第 (i) 维的坐标是多少。方便起见我们假设 (t_ige 0),如果 (t_i<0) 那我们只需将 (c_j=i)(d_j) 都变为其相反数即可。
    • (mn_{i,j}):在一整个长度为 (n) 周期中,如果我们将起点视为源点,那么执行完前 (j) 个命令后,在一个周期中第 (i) 维坐标的最小值是多少,不难发现 (x_i=mn_{i,n})
    • (mx_{i,j}):在一整个长度为 (n) 周期中,如果我们将起点视为源点,那么执行完前 (j) 个命令后,在一个周期中第 (i) 维坐标的最大值是多少,同样地有 (y_i=mx_{i,n})
    • (sum_{i,j}):在一整个长度为 (n) 周期中,如果我们将起点视为源点,那么执行完前 (j) 个命令后,第 (i) 维的坐标是多少。

    首先我们思考一下对于某一维 (i) 上的某个坐标 (x),最少需要多少步才能离开这一维的范围(即,这一维的坐标 ( otin[1,w_i]))。一个比较显然但非常关键的性质是,由于 (t_ige 0),因此如果第一个周期内不能从左边离开场地,那么第二周期起点位置肯定比第一周期更靠右,也就更不可能从右边离开场地,也就是说如果离开时走的步数 (>n),那么我们必定是从右边离开场地的。因此我们考虑枚举小 C 最后一步是在这个长度为 (n) 的周期中哪个指令下离开场地,记为第 (i) 个命令。那么此时此刻已经执行的命令必定是若干个长度为 (n) 的完整的周期加上前 (i) 个命令构成的这段前缀,我们记当前位于第 (K) 个周期(方便起见我们不妨设 (Kge 2)(K=1) 的情况后面再说),那么根据之前的推论,这一步肯定是第 (c_i) 维坐标达到了 (w_{c_i}+1)。又因为第一周期内无法离开场地,因此如果我们记 (s_i) 为第 (i) 起点的坐标,必定有 (s_jin[-x_j+1,w_j]),又因为在前 ((K-1)n+i-1) 步内不能离开场地,因此对于每一维 (j) 可以列出以下四个不等式:

    [egin{cases} s_j+(K-2)t_j+mn_{j,i-1}in[1,w_j]\ s_j+(K-2)t_j+mx_{j,i-1}in[1,w_j]\ s_j+(K-1)t_j+x_jin[1,w_j]\ s_j+(K-1)t_j+y_jin[1,w_j] end{cases} ]

    再加上第 (i) 步第 (c_i) 维坐标需达到 (w_{c_i}+1),因此还有 (s_{c_i}+(K-1)t_{c_i}+sum_{c_i,i-1}=w_{c_i}+1)

    总共是 (5k+1) 个限制,每个限制都可以表示为 (s_jin[L,R]) 的形式,因此我们可以解出 (s_j) 的范围,如果存在某个 (s_j) 的范围为空则表明不可能恰好在第 ((K-1)n+i) 步离开场地,否则合法的坐标数就是 (s_j) 范围的乘积。

    但是直接枚举 (K) 复杂度过高,无法接受。不过注意到一个性质就是如果存在某个坐标经过 (Kn+i) 步离开场地,就必定存在某个坐标经过 ((K-1)n+i) 步离开场地,因此考虑二分最大的 (K) 满足存在某个坐标经过 ((K-1)n+i) 步离开场地,那么我们要求的值就是 (sumlimits_{j=2}^K ext{calc}((j-1)n+i)·((j-1)n+i)),其中 ( ext{calc}(x)) 为满足恰好经过 (x) 步离开场地的坐标个数。暴力算还是 T,不过我们还可以发现,每次解出来的 (s_j(j e c_i)) 的范围区间的左端点都是固定不变的值 (-x_j+1),因此区间长度可以写成关于右端点的一次函数,又区间非空,因此右端点可以写成关于 (K) 的一次函数,因此 ( ext{calc}((j-1)n+i)) 可以看作关于 (j)(k-1) 次函数,再加上前缀和与后面的系数,(sum) 里的东西为关于 (K)(k+1) 次函数,因此可以考虑求出 (2,3,cdots,k+3) 处的函数值然后把多项式插出来即可。

    接下来考虑 (K=1) 的情况,相信聪明的读者们如果理解了 (Kge 2) 的情况,那么 (K=1) 的情况想必是易如反掌了,我们还是可以列出一些关于 (s_j) 的不等式,也就能解出对应 (s_j) 的范围,然后可以乘法原理对应的坐标个数,如果还是不懂那就看代码吧。

    上述算法复杂度是 (nklog n+nk^2),不开 O2 只能获得 80 分的好成绩。

    附:不开 O2 80pts,开 O2 AC 的代码:

    namespace sub2{
    	int x[MAXK+2],y[MAXK+2],t[MAXK+2];
    	int mn[MAXK+2][MAXN+5],mx[MAXK+2][MAXN+5],sum[MAXK+2][MAXN+5];
    	void calc(int r){
    		for(int i=1;i<=n;i++) if(c[i]==r) t[r]+=d[i];
    		if(t[r]<0){
    			t[r]=-t[r];
    			for(int i=1;i<=n;i++) if(c[i]==r) d[i]=-d[i];
    		} int cur=0;
    		for(int i=1;i<=n;i++){
    			if(c[i]==r) cur+=d[i];sum[r][i]=cur;
    			mn[r][i]=min(mn[r][i-1],cur);
    			mx[r][i]=max(mx[r][i-1],cur);
    		} x[r]=mn[r][n];y[r]=mx[r][n];
    //		printf("%d %d
    ",x[r],y[r]);
    	}
    	struct itvl{
    		ll l,r;
    		itvl(ll _l=0,ll _r=0):l(_l),r(_r){}
    		itvl operator &(const itvl &rhs){
    			return itvl(max(l,rhs.l),min(r,rhs.r));
    		}
    	};
    	int calc(int mid,int id){
    		static itvl it[MAXK+2];
    		for(int i=1;i<=k;i++) it[i]=itvl(-x[i]+1,w[i]);
    		for(int i=1;i<=k;i++){
    			it[i]=it[i]&itvl(1-1ll*(mid-2)*t[i]-y[i],w[i]-1ll*(mid-2)*t[i]-y[i]);
    			it[i]=it[i]&itvl(1-1ll*(mid-1)*t[i]-mx[i][id-1],w[i]-1ll*(mid-1)*t[i]-mx[i][id-1]);
    		} it[c[id]]=it[c[id]]&itvl(w[c[id]]+1-1ll*(mid-1)*t[c[id]]-sum[c[id]][id],w[c[id]]+1-1ll*(mid-1)*t[c[id]]-sum[c[id]][id]);
    //		printf("checking %d %d
    ",mid,id);
    //		for(int i=1;i<=k;i++) printf("%lld %lld
    ",it[i].l,it[i].r);
    		int res=1;
    		for(int i=1;i<=k;i++){
    			if(it[i].l>it[i].r) return 0;
    			res=1ll*res*(it[i].r-it[i].l+1)%MOD;
    		} return res;
    	}
    	int ff[10],inv[10];
    	void solve(){
    		for(int i=(inv[0]=inv[1]=1)+1;i<=6;i++) inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
    		for(int i=1;i<=k;i++) calc(i);
    //		for(int i=1;i<=k;i++) printf("%d %d %d
    ",x[i],y[i],t[i]);
    		int res=0;
    		for(int i=1;i<=n;i++) if(d[i]==1){
    			int l=2,r=1e9,p=-1;
    			if(calc(1e9+1,i)) return puts("-1"),void();
    			while(l<=r){
    				int mid=l+r>>1;
    				if(calc(mid,i)) p=mid,l=mid+1;
    				else r=mid-1;
    			} //printf("%d
    ",p);
    			if(~p){
    				for(int j=2;j<=min(p,6);j++){
    //					printf("%d %d %d
    ",j,i,calc(j,i));
    					ff[j]=1ll*calc(j,i)*(1ll*(j-1)*n%MOD+i)%MOD;
    					ff[j]=(ff[j-1]+ff[j])%MOD;
    				} if(p<=6) res=(res+ff[p])%MOD;
    				else{
    					for(int j=2;j<=6;j++){
    						int ss=1;
    						for(int k=2;k<=6;k++) if(j^k){
    							int mul=1ll*(p-k+MOD)*inv[abs(j-k)]%MOD;
    							if(j<k) mul=MOD-mul;ss=1ll*ss*mul%MOD;
    						} res=(res+1ll*ss*ff[j])%MOD;
    					}
    				}
    			}
    		}
    		for(int i=1;i<=n;i++){
    			static itvl it[MAXK+2];
    			for(int j=1;j<=k;j++) it[j]=itvl(1,w[j]);
    			for(int j=1;j<=k;j++){
    				it[j]=it[j]&itvl(1-mn[j][i-1],w[j]-mn[j][i-1]);
    				it[j]=it[j]&itvl(1-mx[j][i-1],w[j]-mx[j][i-1]);
    			} if(!~d[i]){
    				it[c[i]]=it[c[i]]&itvl(0-sum[c[i]][i],0-sum[c[i]][i]);
    			} else {
    				it[c[i]]=it[c[i]]&itvl(w[c[i]]+1-sum[c[i]][i],w[c[i]]+1-sum[c[i]][i]);
    			} int mul=i;
    //			printf("%d:
    ",i);
    //			for(int j=1;j<=k;j++) printf("%lld %lld
    ",it[j].l,it[j].r);
    			for(int j=1;j<=k;j++){
    				if(it[j].l>it[j].r) mul=0;
    				else mul=1ll*mul*(it[j].r-it[j].l+1)%MOD;
    			} res=(res+mul)%MOD;
    		}
    		printf("%d
    ",res);
    	}
    }
    int main(){
    //	freopen("walk4.in","r",stdin);
    	scanf("%d%d",&n,&k);
    	for(int i=1;i<=k;i++) scanf("%d",&w[i]);
    	for(int i=1;i<=n;i++) scanf("%d%d",&c[i],&d[i]);
    	if(sub1::check()) sub1::solve();
    	else sub2::solve();
    	return 0;
    }
    

    接下来考虑加点优化,显然复杂度瓶颈在于二分,注意到在二分检验的过程中,我们要用到很多不等式,不过这些不等式都可以写成 (s_jin[1-Kt_j+B,w_j-Kt_j+B]) 的形式,又根据之前的推理这些区间的交的左端点恰好是 (-x_j+1),因此我们只用考虑右端点的限制,即 (B) 最小的限制即可,由于这些区间的交集非空,必然可以得到 (w_j-Kt_j+Bge -x_j+1),移个项可以得到 (Kt_jle w_j+B+x_j-1),解得 (Klelfloordfrac{w_j+B+x_j-1}{t_j} floor),也就是说这些限制归结到底都可以写成 (Kle X) 的形式,然后对这些 (X) 取个 (min) 即可得到 (K) 的最大值,这样就省去了二分的 (log)

    还有就是上面的代码中插值用了暴力 (k^2) 的插值方法,不过由于下标连续,可以 (mathcal O(k)) 插值,这样常数会小不少。

    最后附上我最后一次提交的完整代码,开了 O2 只需 947ms:

    const int MAXN=5e5;
    const int MAXK=10;
    const int MOD=1e9+7;
    int n,k,c[MAXN+5],d[MAXN+5],w[MAXK+2];
    namespace sub1{
    	bool check(){
    		int flg=1;
    		for(int i=1;i<=k;i++) flg&=(w[i]<=1e6);
    		return flg;
    	}
    	const int MAXW=1e6;
    	const ll INF=0x3f3f3f3f3f3f3f3fll;
    	ll tim[MAXK+2][MAXW+5];
    	int lft[MAXW+5],rit[MAXW+5];
    	void calc(int x){
    		memset(lft,0,sizeof(lft));memset(rit,0,sizeof(rit));
    		int mn=0,mx=0,cur=0;
    		for(int i=1;i<=n;i++) if(c[i]==x) cur+=d[i];
    		if(cur<0){
    			for(int i=1;i<=n;i++) if(c[i]==x) d[i]=-d[i];
    		} cur=0;
    		for(int i=1;i<=n;i++) if(c[i]==x){
    			cur+=d[i];
    			if(cur>mx) rit[cur]=i,mx=cur;
    			if(cur<mn) lft[-cur]=i,mn=cur;
    		}
    		for(int i=1;i<=w[x];i++){
    			tim[x][i]=INF;
    			if(i+mn<=0) chkmin(tim[x][i],(ll)lft[i]);
    			if(i+mx>w[x]) chkmin(tim[x][i],(ll)rit[w[x]+1-i]);
    			if(cur){
    				int bound=w[x]-mx+1;
    				int tt=max((bound-i+cur-1)/cur,0);
    				chkmin(tim[x][i],1ll*tt*n+rit[w[x]+1-(i+tt*cur)]);
    			}
    		}
    	} ll A[MAXW+5],B[MAXW+5];
    	int inv[MAXW+5];
    	void mergesort(int x){
    		int ps=0,c1=0,c2=0;
    		for(int i=1;i<=w[x];i++) if(tim[x][i]>tim[x][i+1]){ps=i;break;}
    		for(int i=ps;~i;i--) A[++c1]=tim[x][i];A[c1+1]=0;
    		for(int i=ps+1;i<=w[x];i++) B[++c2]=tim[x][i];B[c2+1]=0;
    		for(int i=1,p1=1,p2=1;i<=w[x];i++){
    			if(A[p1]>B[p2]) tim[x][i]=A[p1++];
    			else tim[x][i]=B[p2++];
    		}
    	}
    	int cnt[MAXK+5];
    	void solve(){
    		for(int i=1;i<=k;i++) calc(i);
    		for(int i=1;i<=k;i++) mergesort(i);
    		for(int i=(inv[0]=inv[1]=1)+1;i<=MAXW;i++)
    			inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
    		int sm=0;for(int i=1;i<=k;i++) sm+=w[i];
    		bool flg=1;
    		for(int i=1;i<=k;i++) flg&=(tim[i][1]==INF);
    		if(flg) return puts("-1"),void();
    		int res=1,cnt0=k,ans=0;
    		for(int i=1;i<=sm;i++){
    			int x=0;
    			for(int j=1;j<=k;j++) if(tim[j][cnt[j]+1]>tim[x][cnt[x]+1]) x=j;
    			if(!cnt[x]) cnt0--;
    			else res=1ll*res*inv[cnt[x]]%MOD*(cnt[x]+1)%MOD;
    			++cnt[x];
    			if(!cnt0&&tim[x][cnt[x]]) ans=(ans+tim[x][cnt[x]]%MOD*res%MOD*inv[cnt[x]])%MOD;
    		} printf("%d
    ",ans);
    	}
    }
    namespace sub2{
    	int x[MAXK+2],y[MAXK+2],t[MAXK+2];
    	int mn[MAXK+2][MAXN+5],mx[MAXK+2][MAXN+5],sum[MAXK+2][MAXN+5];
    	void calc(int r){
    		for(int i=1;i<=n;i++) if(c[i]==r) t[r]+=d[i];
    		if(t[r]<0){
    			t[r]=-t[r];
    			for(int i=1;i<=n;i++) if(c[i]==r) d[i]=-d[i];
    		} int cur=0;
    		for(int i=1;i<=n;i++){
    			if(c[i]==r) cur+=d[i];sum[r][i]=cur;
    			mn[r][i]=min(mn[r][i-1],cur);
    			mx[r][i]=max(mx[r][i-1],cur);
    		} x[r]=mn[r][n];y[r]=mx[r][n];
    	}
    	struct itvl{
    		ll l,r;
    		itvl(ll _l=0,ll _r=0):l(_l),r(_r){}
    		itvl operator &(const itvl &rhs){
    			return itvl(max(l,rhs.l),min(r,rhs.r));
    		}
    	};
    	int calc(int mid,int id){
    		static itvl it[MAXK+2];
    		for(int i=1;i<=k;i++) it[i]=itvl(-x[i]+1,w[i]);
    		for(int i=1;i<=k;i++){
    			it[i]=it[i]&itvl(1-1ll*(mid-2)*t[i]-y[i],w[i]-1ll*(mid-2)*t[i]-y[i]);
    			it[i]=it[i]&itvl(1-1ll*(mid-1)*t[i]-mx[i][id-1],w[i]-1ll*(mid-1)*t[i]-mx[i][id-1]);
    		} it[c[id]]=it[c[id]]&itvl(w[c[id]]+1-1ll*(mid-1)*t[c[id]]-sum[c[id]][id],w[c[id]]+1-1ll*(mid-1)*t[c[id]]-sum[c[id]][id]);
    		int res=1;
    		for(int i=1;i<=k;i++){
    			if(it[i].l>it[i].r) return 0;
    			res=1ll*res*(it[i].r-it[i].l+1)%MOD;
    		} return res;
    	}
    	int ff[15],ifac[15],pre[15],suf[15];
    	void solve(){
    		for(int i=(ifac[0]=ifac[1]=1)+1;i<=k+3;i++) ifac[i]=1ll*ifac[MOD%i]*(MOD-MOD/i)%MOD;
    		for(int i=1;i<=k+3;i++) ifac[i]=1ll*ifac[i-1]*ifac[i]%MOD;
    		for(int i=1;i<=k;i++) calc(i);
    		bool flg=1;
    		for(int i=1;i<=k;i++) flg&=(!t[i]&&y[i]-x[i]+1<=w[i]);
    		if(flg) return puts("-1"),void();
    		int res=0;
    		for(int i=1;i<=n;i++) if(d[i]==1){
    			if(!calc(2,i)) continue;
    			int p=1e9+1;
    			for(int j=1;j<=k;j++){
    				if(t[j]){
    					chkmin(p,(w[j]+2*t[j]-y[j]+x[j]-1)/t[j]);
    					chkmin(p,(w[j]+t[j]-mx[j][i-1]+x[j]-1)/t[j]);
    				}
    			}
    //			while(l<=r){
    //				int mid=l+r>>1;
    //				if(calc(mid,i)) p=mid,l=mid+1;
    //				else r=mid-1;
    //			}
    			for(int j=2;j<=min(p,k+3);j++){
    				ff[j]=1ll*calc(j,i)*(1ll*(j-1)*n%MOD+i)%MOD;
    				ff[j]=(ff[j-1]+ff[j])%MOD;
    			} if(p<=k+3) res=(res+ff[p])%MOD;
    			else{
    				pre[1]=suf[k+4]=1;
    				for(int j=2;j<=k+3;j++) pre[j]=1ll*pre[j-1]*(p-j+MOD)%MOD;
    				for(int j=k+3;j>>1;j--) suf[j]=1ll*suf[j+1]*(p-j+MOD)%MOD; 
    				for(int j=2;j<=k+3;j++){
    					int mul=1ll*pre[j-1]*suf[j+1]%MOD;
    					mul=1ll*mul*ifac[j-2]%MOD*ifac[k+3-j]%MOD;
    					if((k+3-j)&1) mul=MOD-mul;
    					res=(res+1ll*mul*ff[j])%MOD;
    				}
    			}
    		}
    		for(int i=1;i<=n;i++){
    			static itvl it[MAXK+2];
    			for(int j=1;j<=k;j++) it[j]=itvl(1,w[j]);
    			for(int j=1;j<=k;j++){
    				it[j]=it[j]&itvl(1-mn[j][i-1],w[j]-mn[j][i-1]);
    				it[j]=it[j]&itvl(1-mx[j][i-1],w[j]-mx[j][i-1]);
    			} if(!~d[i]) it[c[i]]=it[c[i]]&itvl(0-sum[c[i]][i],0-sum[c[i]][i]);
    			else it[c[i]]=it[c[i]]&itvl(w[c[i]]+1-sum[c[i]][i],w[c[i]]+1-sum[c[i]][i]);
    			int mul=i;
    			for(int j=1;j<=k;j++){
    				if(it[j].l>it[j].r) mul=0;
    				else mul=1ll*mul*(it[j].r-it[j].l+1)%MOD;
    			} res=(res+mul)%MOD;
    		}
    		printf("%d
    ",res);
    	}
    }
    int main(){
    //	freopen("walk4.in","r",stdin);
    	freopen("walk.in","r",stdin);
    	freopen("walk.out","w",stdout);
    	scanf("%d%d",&n,&k);
    	for(int i=1;i<=k;i++) scanf("%d",&w[i]);
    	for(int i=1;i<=n;i++) scanf("%d%d",&c[i],&d[i]);
    	if(sub1::check()) sub1::solve();
    	else sub2::solve();
    	return 0;
    }
    

    啊啊啊啊啊啊啊我的 E 队怎么就没了呢

  • 相关阅读:
    redis有序集合性能 列表、集合、有序集合
    每天一个linux命令(26):用SecureCRT来上传和下载文件
    每天一个linux命令(25):linux文件属性详解
    每天一个linux命令(24):Linux文件类型与扩展名
    每天一个linux命令(23):Linux 目录结构
    每天一个linux命令(22):find 命令的参数详解
    每天一个linux命令(21):find命令之xargs
    每天一个linux命令(20):find命令之exec
    每天一个linux命令(19):find 命令概览
    每天一个linux命令(18):locate 命令
  • 原文地址:https://www.cnblogs.com/ET2006/p/luogu-P7116.html
Copyright © 2020-2023  润新知