[NOIP2020] 微信步数

  • 思考的过程学到了很多~
  • 枚举第i个维度的第j个格子最终出界,预处理出它出界时的步数,需要统计其他格子有多少个的步数大于它。观察到统计的过程中我们并不关注格子的位次,所以可以先排序再进行二分查找。所有步数都是互异的,因此不需要纠结重复的情况。进一步,我们也不关心枚举的格子的位次呀?所以,我们可以按步数从小到大枚举格子,这样就可以通过双指针以O(\(n^2w\))的时间复杂度拿到80分。实现的过程中,需要时刻保证数据的有效性。如l,r都可能会超过w的范围,以及有些格子是不可能出界的等等。
  • 朴素处理首尾的格子,用拉格朗日插值优化中间有规律的部分,就可以通过本题
#include <bits/stdc++.h>
using namespace std;
const int mod=1000000007;
int w[15],cur[15],l[15],r[15],p[15];
long long s[15][1000005];
unordered_map<int,int>q[15];
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,k;
	cin>>n>>k;
	for(int i=1;i<=k;i++)
	{
		cin>>w[i];
	}
	for(int i=1;i<=n;i++)
	{
		int c,d;
		cin>>c>>d;
		cur[c]+=d;
		l[c]=min(l[c],cur[c]);
		r[c]=max(r[c],cur[c]);
		if(q[c].find(cur[c])==q[c].end())
		{
			q[c][cur[c]]=i;
		}
	}
	if(*min_element(cur+1,cur+k+1)==0&&*max_element(cur+1,cur+k+1)==0)
	{
		cout<<-1<<endl;
		return 0;
	}
	memset(s,0x3f,sizeof(s));
	for(int i=1;i<=k;i++)
	{
		l[i]=-l[i];
		for(int j=1;j<=min(l[i],w[i]);j++)
		{
			s[i][j]=q[i][-j];
		}
		for(int j=1;j<=min(r[i],w[i]);j++)
		{
			s[i][w[i]-j+1]=min(s[i][w[i]-j+1],(long long)q[i][j]);
		}
		if(cur[i]>0&&r[i]<w[i])
		{
			int L=w[i]-r[i]+1,R=w[i]-r[i]+cur[i];
			bool f;
			do
			{
				f=true;
				for(int j=L;j<=R;j++)
				{
					if(j-cur[i]>l[i])
					{
						s[i][j-cur[i]]=s[i][j]+n;
					}
					else
					{
						f=false;
					}
				}
				L-=cur[i];
				R-=cur[i];
			}while(f);
		}
		else if(cur[i]<0&&l[i]<w[i])
		{
			int L=l[i]+cur[i]+1,R=l[i];
			bool f;
			do
			{
				f=true;
				for(int j=L;j<=R;j++)
				{
					if(j-cur[i]<=w[i]-r[i])
					{
						s[i][j-cur[i]]=s[i][j]+n;
					}
					else
					{
						f=false;
					}
				}
				L-=cur[i];
				R-=cur[i];
			}while(f);
		}
	}
	for(int i=1;i<=k;i++)
	{
		sort(s[i]+1,s[i]+w[i]+1);
	}
	long long ans=0;
	for(int i=1;i<=k;i++)
	{
		for(int j=1;j<=k;j++)
		{
			p[j]=1;
		}
		for(int j=1;j<=w[i];j++)
		{
			if(s[i][j]==s[0][0])
			{
				break;
			}
			long long sum=s[i][j];
			for(int d=1;d<=k;d++)
			{
				if(i==d)
				{
					continue;
				}
				while(s[d][p[d]]<s[i][j])
				{
					p[d]++;
				}
				sum=sum*(w[d]-p[d]+1)%mod;
			}
			ans=(ans+sum)%mod;
		}
	}
	cout<<ans<<endl;
	return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int mod=1000000007;
int w[15],cur[15],l[15],r[15],p[15];
vector<long long>raw[15],s[15];
int len[15],lft[15],tmp[15];
long long h[15];
unordered_map<int,int>q[15];
int y[1000005];
long long S[1000005],jc[1000005];
long long t[1000005];
int power(int n,int p)
{
	if(p==0)
	{
		return 1;
	}
	long long tmp=power(n,p/2);
	if(p%2==1)
	{
		return tmp*tmp%mod*n%mod;
	}
	return tmp*tmp%mod;
}
long long lagrange(int m,int k)
{
	S[0]=jc[0]=1;
	for(int i=1;i<=m;i++)
	{
		S[i]=S[i-1]*(k-i)%mod;
		jc[i]=jc[i-1]*i%mod;
	}
	t[m+1]=1;
	for(int i=m;i>=1;i--)
	{
		t[i]=t[i+1]*(k-i)%mod;
	}
	long long ans=0;
	for(int i=1;i<=m;i++)
	{
		long long p=S[i-1]*t[i+1]%mod,q=jc[m-i]*jc[i-1]%mod;
		if((m-i)%2==1)
		{
			q=-q;
		}
		ans=(ans+y[i]*p%mod*power(q,1000000005)%mod)%mod;
	}
	return ans;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	long long n,k;
	cin>>n>>k;
	for(int i=1;i<=k;i++)
	{
		cin>>w[i];
	}
	for(int i=1;i<=n;i++)
	{
		int c,d;
		cin>>c>>d;
		cur[c]+=d;
		l[c]=min(l[c],cur[c]);
		r[c]=max(r[c],cur[c]);
		if(q[c].find(cur[c])==q[c].end())
		{
			q[c][cur[c]]=i;
		}
	}
	long long minn=INT_MAX;
	for(int i=1;i<=k;i++)
	{
		l[i]=-l[i];
		if(l[i]+r[i]>w[i])
		{
			for(int j=1;j<max(w[i]-r[i]+1,1);j++)
			{
				s[i].push_back(q[i][-j]);
			}
			for(int j=max(w[i]-r[i]+1,1);j<=min(l[i],w[i]);j++)
			{
				s[i].push_back(min(q[i][-j],q[i][w[i]-j+1]));
			}
			for(int j=min(l[i],w[i])+1;j<=w[i];j++)
			{
				s[i].push_back(q[i][w[i]-j+1]);
			}
		}
		else
		{
			len[i]=abs(cur[i]);
			if(cur[i]==0)
			{
				for(int j=w[i]-r[i]+1;j<=w[i];j++)
				{
					s[i].push_back(q[i][w[i]-j+1]);
				}
				for(int j=1;j<=l[i];j++)
				{
					s[i].push_back(q[i][-j]);
				}
				continue;
			}
			if(cur[i]>0)
			{
				for(int j=w[i]-r[i]+1;j<=w[i];j++)
				{
					s[i].push_back(q[i][w[i]-j+1]);
					if(raw[i].size()<len[i])
					{
						raw[i].push_back(q[i][w[i]-j+1]);
					}
				}
				for(int j=1;j<=l[i];j++)
				{
					s[i].push_back(q[i][-j]);
				}
			}
			else
			{
				for(int j=l[i];j>=1;j--)
				{
					s[i].push_back(q[i][-j]);
					if(raw[i].size()<len[i])
					{
						raw[i].push_back(q[i][-j]);
					}
				}
				for(int j=w[i]-r[i]+1;j<=w[i];j++)
				{
					s[i].push_back(q[i][w[i]-j+1]);
				}
			}
			reverse(raw[i].begin(),raw[i].end());
			lft[i]=(w[i]-l[i]-r[i])%len[i];
			h[i]=(w[i]-l[i]-r[i])/len[i];
			minn=min(minn,h[i]);
		}
	}
	if(*min_element(cur+1,cur+k+1)==0&&*max_element(cur+1,cur+k+1)==0&&minn==INT_MAX)
	{
		cout<<-1<<endl;
		return 0;
	}
	for(int i=1;i<=k;i++)
	{
		sort(s[i].begin(),s[i].end());
		if(h[i]==minn)
		{
			tmp[i]=lft[i];
		}
		else
		{
			tmp[i]=len[i];
		}
	}
	long long ans=0;
	for(int i=1;i<=k;i++)
	{
		for(int j=1;j<=k;j++)
		{
			p[j]=0;
		}
		for(int j=0;j<s[i].size();j++)
		{
			long long sum=s[i][j];
			for(int d=1;d<=k;d++)
			{
				if(i==d)
				{
					continue;
				}
				while(p[d]<s[d].size()&&s[d][p[d]]<s[i][j])
				{
					p[d]++;
				}
				sum=sum*(w[d]-p[d])%mod;
			}
			ans=(ans+sum)%mod;
		}
	}
	for(int i=1;i<=k;i++)
	{
		if(len[i])
		{
			for(int j=1;j<=k;j++)
			{
				p[j]=0;
			}
			for(int j=0;j<tmp[i];j++)
			{
				long long sum=(raw[i][j]+(minn+1)*n%mod)%mod;
				for(int d=1;d<=k;d++)
				{
					if(i==d)
					{
						continue;
					}
					while(p[d]<tmp[d]&&raw[d][p[d]]<raw[i][j])
					{
						p[d]++;
					}
					sum=sum*(w[d]-s[d].size()-minn*len[d]-p[d])%mod;
				}
				ans=(ans+sum)%mod;
			}
		}
	}
	for(int i=1;i<=k;i++)
	{
		if(len[i])
		{
			for(int j=1;j<=min(minn,k+2);j++)
			{
				y[j]=y[j-1];
				for(int d=1;d<=k;d++)
				{
					p[d]=0;
				}
				for(int l=0;l<len[i];l++)
				{
					long long sum=raw[i][l]+j*n;
					for(int d=1;d<=k;d++)
					{
						if(i==d)
						{
							continue;
						}
						while(p[d]<len[d]&&raw[d][p[d]]<raw[i][l])
						{
							p[d]++;
						}
						sum=sum*(w[d]-s[d].size()-(j-1)*len[d]-p[d])%mod;
					}
					y[j]=(y[j]+sum)%mod;
				}
			}
			ans=(ans+lagrange(min(minn,k+2),minn)%mod)%mod;
		}
	}
	cout<<(ans+mod)%mod<<endl;
	return 0;
}
posted @ 2025-02-23 19:24  D06  阅读(19)  评论(0)    收藏  举报
//雪花飘落效果