把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P7116 [NOIP2020] 微信步数

题面传送门
这东西感觉一脸看上去不可做好吧,步数啥的肯定差分一下比较好算。
差分后求出至少要走\(k\)步的区域大小是多少,容易发现这个是一个\(k\)维的长方体(好像不能这么说?)然后一步一步模拟就可以做到\(O(nkw)\)的复杂度。然后和暴力同分
这个循环肯定不是白给的,看上去有一定的规律,因此第一次循环暴力枚举,然后发现从第二次开始,每次中造成贡献是哪一步是恒定的,而每次贡献会使至少一个\(w\)减少\(1\)。因此可以先把所有造成贡献的步预处理出来,然后暴力遍历这些步数,计算贡献,可以做到\(O(nk+wk^2)\)的复杂度,常数较小可以过\(80\)
全部数据中\(w\)变得很大所以不太可做。但是考虑每一轮中造成的贡献显然是一个\(k\)次多项式,因此可以对前面整数轮拉格朗日插值,后面的零散轮暴力,就可以做到\(O(nk^2)\)
代码感觉还是比较好写的。
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (5000000+5)
#define M (10+5)
#define K (3000000+5)
#define mod 1000000007
#define Mod (mod-1)
#define eps (1e-9)
#define ull unsigned ll
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (1ll*rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int n,k,W[M],Op[M],Fl,Mx[M],My[M],X[N],Y[N],P[N],H,G[N],La,F[M],Mn;ll Ans,Ns,Px[M],Py[M];
I ll mpow(ll x,int y=mod-2){ll Ans=1;while(y) y&1&&(Ans=Ans*x%mod),y>>=1,x=x*x%mod;return Ans;}
I ll LG(int x){
	ll T1,T2,ToT=0;int i,j;for(i=1;i<=k+2;i++){
		T1=T2=1;for(j=1;j<=k+2;j++) i^j&&(T1=T1*(x-j)%mod,T2=T2*(i-j)%mod);ToT+=T1*Py[i]%mod*mpow(T2)%mod;
	}return (ToT%mod+mod)%mod;
}
I void END(){printf("%lld\n",(Ans%mod+mod)%mod);exit(0);}
int main(){
	freopen("1.in","r",stdin);
	int i,j,h;scanf("%d%d",&n,&k);for(i=1;i<=k;i++) scanf("%d",&W[i]);for(i=1;i<=n;i++) scanf("%d%d",&X[i],&Y[i]);
	for(i=1;i<=n;i++){
		Op[X[i]]+=Y[i];if(Op[X[i]]>Mx[X[i]]) {Ns=1;for(j=1;j<=k;j++) Ns=Ns*W[j]%mod;W[X[i]]--;Ans+=Ns*(i-La)%mod;La=i;if(!W[X[i]])END();Mx[X[i]]=Op[X[i]];}
		if(Op[X[i]]<My[X[i]]) {Ns=1;for(j=1;j<=k;j++) Ns=Ns*W[j]%mod;Ans+=Ns*(i-La)%mod;La=i;W[X[i]]--;if(!W[X[i]]) END();My[X[i]]=Op[X[i]];}
	}
	for(i=1;i<=k;i++) if(Op[i]) {Fl=1;break;}if(!Fl){puts("-1");return 0;}La-=n;
	for(i=1;i<=n;i++) {
		Op[X[i]]+=Y[i];if(Op[X[i]]>Mx[X[i]]) {Ns=1;for(j=1;j<=k;j++) Ns=Ns*W[j]%mod;W[X[i]]--;Ans+=Ns*(i-La)%mod;if(!W[X[i]])END();Mx[X[i]]=Op[X[i]];P[++H]=X[i];G[H]=i-La;La=i;}
		if(Op[X[i]]<My[X[i]]) {Ns=1;for(j=1;j<=k;j++) Ns=Ns*W[j]%mod;Ans+=Ns*(i-La)%mod;W[X[i]]--;if(!W[X[i]])END();My[X[i]]=Op[X[i]];P[++H]=X[i];G[H]=i-La;La=i;}
	}for(i=1;i<=H;i++) F[P[i]]++;Mn=1e9;for(i=1;i<=k;i++) F[i]&&(Mn=min(Mn,W[i]/F[i]));
	for(h=1;h<=k+2;h++){Px[h]=h;Py[h]=Py[h-1];
		for(i=1;i<=H;i++) {Ns=1;for(j=1;j<=k;j++) Ns=Ns*W[j]%mod;W[P[i]]--;Py[h]+=Ns*G[i]%mod;Ans+=Ns*G[i]%mod;if(!W[P[i]]) END();}Py[h]%=mod;
	}for(i=1;i<=k;i++) W[i]+=F[i]*(k+2-Mn);Ans-=Py[k+2];Ans+=LG(Mn);for(i=1;i<=k;i++) if(!W[i])END();
	while(1){
		for(i=1;i<=H;i++) {Ns=1;for(j=1;j<=k;j++) Ns=Ns*W[j]%mod;W[P[i]]--;Ans+=Ns*G[i]%mod;if(!W[P[i]]) END();}
	}
}
posted @ 2022-06-15 22:46  275307894a  阅读(36)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end