NOI Online #2 入门组

未了

题意:

一座高\(n\)米的山,每秒爬\(v\)米,有\(n\)个魔法,第\(i\)个魔法可以让你爬到\(a_i\)米时传送回山脚,\(m\)次询问,每次问最少用多少个魔法,才能让爬山时间大于\(t_i\)

\(n,m\leq 10^5\)

题解:

\(a_i\)从大到小排序,前缀和二分。\(O(nlogn)\)

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
	const int N=3e5+10;
	int n,m,len,v;
	int a[N],s[N];
	inline void main()
	{
		ios::sync_with_stdio(0);
		cin.tie(0),cout.tie(0);
		int n,len,v;
		cin>>n>>len>>v;
		for(int i=1;i<=n;++i) cin>>a[i];
		sort(a+1,a+n+1);
		for(int i=1;i<=n;++i) s[i]=s[i-1]+a[n-i+1];
		cin>>m;
		for(int i=1;i<=m;++i)
		{
			int x;cin>>x;
			x=x*v;
			x-=len;
			if(x>=s[n]) cout<<"-1\n";
			else
			{
				int t=upper_bound(s+0,s+n+1,x)-s;
				cout<<t<<'\n';
			}
		}
	}
}
signed main()
{
	red::main();
	return 0;
}

荆轲刺秦王

题意:

\(n*m\)的地图上荆轲要去刺秦王,荆轲每秒可以向周围八个格子移动一步,地图上有卫兵,可以发现曼哈顿距离小于\(a_{i,j}\)范围内的格子的入侵者。

荆轲可以用技能:

\(1.\)隐身,一秒内不被卫兵发现

\(2.\)瞬移,朝上下左右某个方向移动\(d\)

分别能用\(c1,c2\)

问荆轲最短几步内能刺杀秦王,步数最短的情况下,使用两种技能总次数最少,前面的前提下,隐身次数最少。

\(n,m,d,a_{i,j}\leq 350,c1,c2\leq 15\)

题解:

用差分处理曼哈顿距离,预处理出哪些格子必须隐身才能走过去。

然后就是裸\(bfs\)

\(O(n*m^2+n*m*c1*c2)\)

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
	const int N=350+10,inf=2e9;
	int a[N][N],cf[N][N];
	int n,m,c1,c2,d;
	int stx,sty,edx,edy;
	struct node
	{
		int x,y,s1,s2,dis;
	};
	queue<node> q;
	bool vis[355][355][16][16];
	int dx[8]={-1,-1,0,1,1,1,0,-1},dy[8]={0,1,1,1,0,-1,-1,-1};
	int ans1,ans2,ans3;
	inline void bfs()
	{
		q.push((node){stx,sty,0,0,0});
		ans1=inf;
		while(!q.empty())
		{
			node now=q.front();
			q.pop();
			int x=now.x,y=now.y,s1=now.s1,s2=now.s2,dis=now.dis;
			//cout<<x<<' '<<y<<' '<<dis<<endl;
			if(vis[x][y][s1][s2]) continue;
			vis[x][y][s1][s2]=1;
			if(x==edx&&y==edy)
			{
				if(dis<ans1||(dis==ans1&&s1+s2<ans2+ans3)||(dis==ans1&&s1+s2==ans2+ans3&&s1<ans2)) 
					ans1=dis,ans2=s1,ans3=s2;
			}
			if(dis>ans1) break;
			for(int k=0;k<8;++k)
			{
				int tx=x+dx[k],ty=y+dy[k],ts1=s1,ts2=s2,tdis=dis+1;
				//cout<<tx<<' '<<ty<<"!!"<<endl;
				if(a[tx][ty]==-1||tx<1||tx>n||ty<1||ty>m) continue;
				ts1+=a[tx][ty];
				if(ts1>c1||ts2>c2) continue;
				if(vis[tx][ty][ts1][ts2]) continue;
				q.push((node){tx,ty,ts1,ts2,tdis});
			}
			for(int k=0;k<8;k+=2)
			{
				int tx=x+dx[k]*d,ty=y+dy[k]*d,ts1=s1,ts2=s2+1,tdis=dis+1;
				if(a[tx][ty]==-1||tx<1||tx>n||ty<1||ty>m) continue;
				ts1+=a[tx][ty];
				if(ts1>c1||ts2>c2) continue;
				if(vis[tx][ty][ts1][ts2]) continue;
				q.push((node){tx,ty,ts1,ts2,tdis});
			}
		}
		if(ans1==inf) cout<<"-1\n";
		else cout<<ans1<<' '<<ans2<<' '<<ans3<<'\n';
	}
	inline void main()
	{
		ios::sync_with_stdio(0);
		cin.tie(0),cout.tie(0);
		cin>>n>>m>>c1>>c2>>d;
		for(int i=1;i<=n;++i)
		{
			for(int j=1;j<=m;++j)
			{
				string ch;cin>>ch;
				if(ch[0]=='S') stx=i,sty=j;
				if(ch[0]=='T') edx=i,edy=j;
				if(ch[0]>='0'&&ch[0]<='9')
				{
					int num=0;
					for(int k=0;k<ch.length();++k) num=num*10+ch[k]-'0';
					--num;
					a[i][j]=-1;
					for(int k=i-num,l=0;k<=i;++k,++l)
					{
						if(k>=1)
						{
							++cf[k][max(1ll,j-l)];
							if(j+l+1<=m) --cf[k][j+l+1];
						}
					}
					for(int k=i+1,l=num-1;k<=min(n,i+num);++k,--l)
					{
						++cf[k][max(1ll,j-l)];
						if(j+l+1<=m) --cf[k][j+l+1];
					}
				}
			}
		}
		for(int i=1;i<=n;++i)
		{
			for(int j=1;j<=m;++j)
			{
				cf[i][j]+=cf[i][j-1];
				if(cf[i][j]>0&&!a[i][j]) a[i][j]=1;
				//cout<<a[i][j]<<" \n"[j==m];
			}
		}
		bfs();
	}
}
signed main()
{
	red::main();
	return 0;
}

建设城市

题意:

\(2n\)栋楼,每栋楼高是\(1\sim m\),要求前\(n\)栋楼高度不下降,后\(n\)栋楼高度不上升,且编号为\(x,y\)的楼高度相等,求方案数。

\(n,m\leq 10^5\)

\(x\leq n,y>n\)为例:

枚举\(x,y\)的高度\(k\)

\(ans=\sum_{k=1}^mf(x-1,k)*f(n-x,m-k+1)*f(y-n-1,m-k+1)*f(2*n-y,k)\)

其中\(f(n,m)\)表示\(n\)栋楼,取值范围是\(1\sim m\),且不下降的方案数。

这个方案数其实就是\(n\)个物品分成\(m\)组,可以有空组的方案数。

\(O(2*n+m)\)

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
	const int N=5e5+10,mod=998244353,inf=2e9;
	int n,m,x,y;
	int fac[N],inv[N];
	inline int fast(int x,int k)
	{
		int ret=1;
		while(k)
		{
			if(k&1) ret=ret*x%mod;
			x=x*x%mod;
			k>>=1;
		}
		return ret;
	}
	inline int C(int n,int m)
	{
		if(n<m) return 0;
		return fac[n]*inv[m]%mod*inv[n-m]%mod;
	}
	inline int cb(int n,int m)
	{
		//cout<<n<<' '<<m<<' '<<C(n+m-1,m-1)<<"!!"<<endl;
		//x1+x2+…+xm=n
		//
		return C(n+m-1,m-1);
	}
	inline void work1()
	{
		int ans=0;
		for(int k=1;k<=m;++k)
		{
			int tmp=cb(x-1,k)*cb(n-y,m-k+1)%mod*cb(n,m)%mod;
			ans=(ans+tmp)%mod;
		}
		cout<<ans<<'\n';
	}
	inline void work2()
	{
		int ans=0;
		for(int k=1;k<=m;++k)
		{
			int tmp=cb(x-1,k)*cb(n-x,m-k+1)%mod*cb(2*n-y,k)%mod*cb(y-n-1,m-k+1)%mod;
			//cout<<k<<' '<<cb(x-1,k)<<' '<<cb(n-x,m-k+1)<<' '<<cb(y-n-1,m-k+1)<<' '<<cb(2*n-y,k)<<endl;
			ans=(ans+tmp)%mod;
		}
		cout<<ans<<'\n';
	}
	inline void init(int n)
	{
		fac[0]=inv[0]=1;
		for(int i=1;i<=n;++i) fac[i]=fac[i-1]*i%mod;
		inv[n]=fast(fac[n],mod-2);
		for(int i=n-1;i>=1;--i) inv[i]=inv[i+1]*(i+1)%mod;
	}
	inline void main()
	{
		ios::sync_with_stdio(0);
		cin.tie(0),cout.tie(0);
		cin>>m>>n>>x>>y;
		init(2*n+m);
		if(x>y) swap(x,y);
		if(x>n)
		{
			x=2*n-x+1,y=2*n-y+1;
			swap(x,y);
		}
		if(y<=n) work1();
		else work2();
	}
}
signed main()
{
	red::main();
	return 0;
}
/*
3 2 3 4

*/
posted @ 2022-05-12 09:27  lovelyred  阅读(33)  评论(0编辑  收藏  举报