2024初三集训模拟测试2

2024初三集训模拟测试2

T0 谜之阶乘 100pts

T1 小P的2048 10pts

  • 大模拟,没什么好说的。

    • 注意可以同时合并多对数字,但不能连续合并。
    点击查看代码
    ll a[10][10];
    queue<ll>q;
    int main()
    {
    	ll n,m,x1,y1,v1,x2,y2,v2,d,k,v,sum=0,ans=0,r,num,flag,i,j,h;  
    	cin>>n>>m>>x1>>y1>>v1>>x2>>y2>>v2;
    	a[x1][y1]=v1;
    	a[x2][y2]=v2;
    	for(h=1;h<=m;h++)
    	{
    		cin>>d>>k>>v;
    		r=num=flag=0;
    		if(d==0)
    		{
    			for(j=1;j<=n;j++)
    			{
    				for(i=1;i<=n;i++)
    				{
    					if(a[i][j]!=0)
    					{
    						if(1<=i-1&&a[i-1][j]==0)
    						{
    							flag=1;
    						}
    						q.push(a[i][j]);
    					}
    				}
    				for(i=1;i<=n;i++)
    				{
    					a[i][j]=(q.empty()==0)?q.front():0;
    					if(q.empty()==0)
    					{
    						q.pop();
    					}
    				}
    			}
    			for(j=1;j<=n;j++)
    			{
    				for(i=1;i<=n;i++)
    				{
    					if(i+1<=n&&a[i][j]==a[i+1][j]&&a[i][j]!=0)
    					{
    						flag=1;
    						a[i][j]*=2;
    						a[i+1][j]=0;
    						ans+=a[i][j];
    					}
    				}
    			}
    			for(j=1;j<=n;j++)
    			{
    				for(i=1;i<=n;i++)
    				{
    					if(a[i][j]!=0)
    					{
    						if(1<=i-1&&a[i-1][j]==0)
    						{
    							flag=1;
    						}
    						q.push(a[i][j]);
    					}
    				}
    				for(i=1;i<=n;i++)
    				{
    					a[i][j]=(q.empty()==0)?q.front():0;
    					if(q.empty()==0)
    					{
    						q.pop();
    					}
    					r+=(a[i][j]==0);
    				}
    			}
    		}
    		if(d==1)
    		{
    			for(j=1;j<=n;j++)
    			{
    				for(i=n;i>=1;i--)
    				{
    					if(a[i][j]!=0)
    					{
    						if(i+1<=n&&a[i+1][j]==0)
    						{
    							flag=1;
    						}
    						q.push(a[i][j]);
    					}
    				}
    				for(i=n;i>=1;i--)
    				{
    					a[i][j]=(q.empty()==0)?q.front():0;
    					if(q.empty()==0)
    					{
    						q.pop();
    					}
    				}
    			}
    			for(j=1;j<=n;j++)
    			{
    				for(i=n;i>=1;i--)
    				{
    					if(1<=i-1&&a[i][j]==a[i-1][j]&&a[i][j]!=0)
    					{
    						flag=1;
    						a[i][j]*=2;
    						a[i-1][j]=0;
    						ans+=a[i][j];
    					}
    				}
    			}
    			for(j=1;j<=n;j++)
    			{
    				for(i=n;i>=1;i--)
    				{
    					if(a[i][j]!=0)
    					{
    						if(i+1<=n&&a[i+1][j]==0)
    						{
    							flag=1;
    						}
    						q.push(a[i][j]);
    					}
    				}
    				for(i=n;i>=1;i--)
    				{
    					a[i][j]=(q.empty()==0)?q.front():0;
    					if(q.empty()==0)
    					{
    						q.pop();
    					}
    					r+=(a[i][j]==0);
    				}
    			}
    		}
    		if(d==2)
    		{
    			for(i=1;i<=n;i++)
    			{
    				for(j=1;j<=n;j++)
    				{
    					if(a[i][j]!=0)
    					{
    						if(1<=j-1&&a[i][j-1]==0)
    						{
    							flag=1;
    						}
    						q.push(a[i][j]);
    					}
    				}
    				for(j=1;j<=n;j++)
    				{
    					a[i][j]=(q.empty()==0)?q.front():0;
    					if(q.empty()==0)
    					{
    						q.pop();
    					}
    				}
    			}
    			for(i=1;i<=n;i++)
    			{
    				for(j=1;j<=n;j++)
    				{
    					if(j+1<=n&&a[i][j]==a[i][j+1]&&a[i][j]!=0)
    					{
    						flag=1;
    						a[i][j]*=2;
    						a[i][j+1]=0;
    						ans+=a[i][j];
    					}
    				}
    			}
    			for(i=1;i<=n;i++)
    			{
    				for(j=1;j<=n;j++)
    				{
    					if(a[i][j]!=0)
    					{
    						if(1<=j-1&&a[i][j-1]==0)
    						{
    							flag=1;
    						}
    						q.push(a[i][j]);
    					}
    				}
    				for(j=1;j<=n;j++)
    				{
    					a[i][j]=(q.empty()==0)?q.front():0;
    					if(q.empty()==0)
    					{
    						q.pop();
    					}
    					r+=(a[i][j]==0);
    				}
    			}
    		}
    		if(d==3)
    		{
    			for(i=1;i<=n;i++)
    			{
    				for(j=n;j>=1;j--)
    				{
    					if(a[i][j]!=0)
    					{
    						if(j+1<=n&&a[i][j+1]==0)
    						{
    							flag=1;
    						}
    						q.push(a[i][j]);
    					}
    				}
    				for(j=n;j>=1;j--)
    				{
    					a[i][j]=(q.empty()==0)?q.front():0;
    					if(q.empty()==0)
    					{
    						q.pop();
    					}
    				}
    			}
    			for(i=1;i<=n;i++)
    			{
    				for(j=n;j>=1;j--)
    				{
    					if(1<=j-1&&a[i][j]==a[i][j-1]&&a[i][j]!=0)
    					{
    						flag=1;
    						a[i][j]*=2;
    						a[i][j-1]=0;
    						ans+=a[i][j];
    					}
    				}
    			}
    			for(i=1;i<=n;i++)
    			{
    				for(j=n;j>=1;j--)
    				{
    					if(a[i][j]!=0)
    					{
    						if(j+1<=n&&a[i][j+1]==0)
    						{
    							flag=1;
    						}
    						q.push(a[i][j]);
    					}
    				}
    				for(j=n;j>=1;j--)
    				{
    					a[i][j]=(q.empty()==0)?q.front():0;
    					if(q.empty()==0)
    					{
    						q.pop();
    					}
    					r+=(a[i][j]==0);
    				}
    			}
    		}
    		if(flag==1&&r!=0)
    		{
    			sum++;
    			for(i=1;i<=n;i++)
    			{
    				for(j=1;j<=n;j++)
    				{
    					num+=(a[i][j]==0);
    					if(num==k%r+1)
    					{
    						a[i][j]=v;
    						break;
    					}
    				}
    				if(num==k%r+1)
    				{
    					break;
    				}
    			}
    		}
    		else
    		{
    			break;
    		}
    	}
    	cout<<sum<<endl;
    	cout<<ans<<endl;
    	return 0;
    }
    

T2 子集 0pts

  • 部分分

    • 20% :由于 nk 为偶数,故在待选递增序列中左右端各依次取 n2k 个数即可。

      点击查看代码
      if((n/k)%2==0)
      {
      	l=0;
      	r=n+1;
      	cout<<"Yes"<<endl;
      	for(i=1;i<=k;i++)
      	{
      		for(j=1;j<=(n/k)/2;j++)
      		{
      			l++;
      			cout<<l<<" ";
      			r--;
      			cout<<r<<" ";
      		}
      		cout<<endl;
      	}
      }
      
  • 正解

    • n=k1n(n+1)20(modk) 时,无解。
    • k=1 时,依次输出 1n 即可。
    • nk 为偶数时,在待选递增序列中左右端各依次取 n2k 个数即可。
    • nk 为奇数时,考虑尽可能减少因 nk 为奇数而对答案产生的影响,这就要求我们尽可能缩小 nk 的范围。为方便代码书写,我们选择每个子集中特殊构造 3 个数,剩下的 nk3 个数处理方式同 nk 为偶数时的构造方式。具体地,我们单独选出 13k 来进行特殊构造。此时问题转化为了 3k 个连续的自然数如何将其分为 k 组,每组恰好只有 3 个数,且每组内数的总和相等。其中一种构造方式为 {(1ik12):i+(3k+12+i)+(3k+12i)=3(3k+1)2(k+12ik):i+(k+12+i)+(4k+12i)=3(3k+1)2
    点击查看代码
    int main()
    {
    	ll t,n,k,i,j,l,r,h;
    	cin>>t;
    	for(h=1;h<=t;h++)
    	{
    		cin>>n>>k;
    		if((n!=1&&n==k)||(n*(n+1)/2)%k!=0)
    		{
    			cout<<"No"<<endl;
    		}
    		else
    		{
    			cout<<"Yes"<<endl;
    			if(k==1)
    			{
    				for(i=1;i<=n;i++)
    				{
    					cout<<i<<" ";
    				}
    				cout<<endl;
    			}
    			else
    			{
    				if((n/k)%2==0)
    				{
    					l=0;
    					r=n+1;
    					for(i=1;i<=k;i++)
    					{
    						for(j=1;j<=(n/k)/2;j++)
    						{
    							l++;
    							cout<<l<<" ";
    							r--;
    							cout<<r<<" ";
    						}
    						cout<<endl;
    					}
    				}
    				else
    				{
    					l=3*k;
    					r=n+1;
    					for(i=1;i<=(k-1)/2;i++)
    					{
    						for(j=1;j<=(n/k-3)/2;j++)
    						{
    							l++;
    							cout<<l<<" ";
    							r--;
    							cout<<r<<" ";
    						}
    						cout<<i<<" "<<(3*k+1)/2+i<<" "<<3*k+1-2*i<<endl;
    					}
    					for(i=(k+1)/2;i<=k;i++)
    					{
    						for(j=1;j<=(n/k-3)/2;j++)
    						{
    							l++;
    							cout<<l<<" ";
    							r--;
    							cout<<r<<" ";
    						}
    						cout<<i<<" "<<(k+1)/2+i<<" "<<4*k+1-2*i<<endl;
    					}
    				}
    			}
    		}
    	}
    	return 0;
    }
    

T3 混凝土粉末 0pts

  • 部分分
    • 84pts
      • 在线做法

        • 询问的本质是对之前的所有修改操作进行修改,找到第一个所得高度 y 的位置的时间,若没有找到则为 0
        • 枚举并统计之前的所有修改操作对当前查询的影响即可。
        • 最坏时间复杂度为 O(q2) ,带 14 的常数。
        点击查看代码
        struct node
        {
        	ll l,r,h,id;
        }a[1000001];
        int main()
        {
        	ll n,q,m=0,pd,x,y,sum,ans,i,j;
        	cin>>n>>q;
        	for(i=1;i<=q;i++)
        	{
        		cin>>pd;
        		if(pd==1)
        		{
        			m++;
        			cin>>a[m].l>>a[m].r>>a[m].h;
        			a[m].id=i;
        		}
        		else
        		{
        			cin>>x>>y;
        			sum=ans=0;
        			for(j=1;j<=m;j++)
        			{
        				if(a[j].l<=x&&x<=a[j].r)
        				{
        					sum+=a[j].h;
        					if(sum>=y)
        					{
        						ans=a[j].id;
        						break;
        					}
        				}
        			}
        			cout<<ans<<endl;
        		}
        	}
        	return 0;
        }
        
  • 正解
    • 离线做法
      • 考虑优化暴力的在线做法。将所有操作进行离线下来,同样统计之前的所有修改操作对当前查询的影响。
        • 二分树状数组
          • 树状数组记录每个点每个时刻的高度,然后二分即可。用扫描线的思想将二维树状数组压成一维数组。具体地,对于一段修改的区间 [li,ri] ,当扫描到 l 时,在 l 位置上加上 hi ,增加影响;当扫描到 r+1 时,在 r+1 位置上减去 hi ,消除影响。

            点击查看代码
            ll pd[2000001],c[2000001],ans[2000001];
            vector<pair<ll,ll> >a[2000001],ask[2000001];
            ll lowbit(ll x)
            {
            	return (x&(-x));
            }
            void add(ll n,ll x,ll key)
            {
            	for(ll i=x;i<=n;i+=lowbit(i))
            	{
            		c[i]+=key;
            	}
            }
            ll getsum(ll x)
            {
            	ll ans=0;
            	for(ll i=x;i>=1;i-=lowbit(i))
            	{
            		ans+=c[i];
            	}
            	return ans;
            }
            int main()
            {
            	ll n,q,l,r,mid,h,i,j;
            	cin>>n>>q;
            	for(i=1;i<=q;i++)
            	{
            		cin>>pd[i]>>l>>r;
            		if(pd[i]==1)
            		{
            			cin>>h;
            			a[l].push_back(make_pair(i,h));
            			a[r+1].push_back(make_pair(i,-h));
            		}
            		else
            		{
            			ask[l].push_back(make_pair(i,r));
            		}
            	}
            	for(i=1;i<=n;i++)
            	{
            		for(j=0;j<a[i].size();j++)
            		{
            			add(q,a[i][j].first,a[i][j].second);
            		}
            		for(j=0;j<ask[i].size();j++)
            		{
            			l=1;
            			r=ask[i][j].first;
            			ans[ask[i][j].first]=0;
            			while(l<=r)
            			{
            				mid=(l+r)/2;
            				if(getsum(mid)<ask[i][j].second)
            				{
            					l=mid+1;
            				}
            				else
            				{
            					ans[ask[i][j].first]=mid;
            					r=mid-1;
            				}
            			}
            		}
            	}
            	for(i=1;i<=q;i++)
            	{
            		if(pd[i]==2)
            		{
            			cout<<ans[i]<<endl;
            		}
            	}
            	return 0;
            }
            
        • 树状数组或线段树上二分
        • 整体二分
    • 在线做法
      • 主席树

T4 排水系统 0pts

  • 弱化: luogu P7113 [NOIP2020] 排水系统

  • 部分分

    • 7pts :特判输出样例 1,3
  • 正解

    • fi 表示在不考虑堵塞情况下,经过 i 点的污水总吨数。
    • 由于若 (x,y) 堵塞,经过 x 点经过的污水总吨数不变,故当 (x,y) 堵塞时,经过 y 点的污水总吨数减少了 fxdoutx ,经过 x 点的其他子节点的污水总吨数增加了 fxdoutx1fxdoutx=fxdoutx(doutx1) 。将 fxdoutxfxdoutx(doutx1) 放在原图上,计算出原始期望总吨数,可以得到新的 f
    • 但枚举 x 点的其他子节点时间复杂度会爆炸,但 x 点的其他子节点每个增加 fxdoutx(doutx1) 可以转化为从 x 点增加 fxdoutx(doutx1)×doutx=fxdoutx1y 点减少了 fxdoutx+fxdoutx(doutx1)=fxdoutx1 ,然后再转移到 x 点的所有子节点。
      • 此时忽略了 (x,y) 的堵塞,因为从 x 流向 y 的一部分弥补了 y 少的部分。
    点击查看代码
    const ll p=998244353;
    struct node
    {
    	ll nxt,to,w;
    }e[500000];
    ll head[500000],f[2][500000],dout[500000],din[3][500000],cnt=0;
    ll qpow(ll a,ll b,ll p)
    {
    	ll ans=1;
    	while(b>0)
    	{
    		if(b&1)
    		{
    			ans=ans*a%p;
    		}
    		b>>=1;
    		a=a*a%p;
    	}
    	return ans;
    }
    void add(ll u,ll v,ll  w)
    {
    	cnt++;
    	e[cnt].nxt=head[u];
    	e[cnt].to=v;
    	e[cnt].w=w;
    	head[u]=cnt;
    }
    void top_sort1(ll n,ll din[],ll f[])
    {
    	queue<ll>q;
    	ll x,i,ls;
    	for(i=1;i<=n;i++)
    	{
    		if(din[i]==0)
    		{
    			q.push(i);
    		}
    	}
    	while(q.empty()==0)
    	{
    		x=q.front();
    		q.pop();
    		ls=f[x]*qpow(dout[x],p-2,p)%p;
    		for(i=head[x];i!=0;i=e[i].nxt)
    		{
    			din[e[i].to]--;
    			f[e[i].to]=(f[e[i].to]+ls)%p;
    			if(din[e[i].to]==0)
    			{
    				q.push(e[i].to);
    			}
    		}
    	}
    }
    void top_sort2(ll n,ll din[],ll sum)
    {   
    	queue<ll>q;
    	ll x,i,ls,inv=qpow(sum,p-2,p);
    	for(i=1;i<=n;i++)
    	{
    		if(din[i]==0)
    		{
    			q.push(i);
    		}
    	}
    	while(q.empty()==0)
    	{
    		x=q.front();
    		q.pop();
    		ls=f[0][x]*qpow(dout[x]-1,p-2,p)%p;
    		for(i=head[x];i!=0;i=e[i].nxt)
    		{
    			din[e[i].to]--;
    			f[1][x]=(f[1][x]+(inv*e[i].w%p)*ls%p)%p;
    			f[1][e[i].to]=(f[1][e[i].to]-(inv*e[i].w%p)*ls%p+p)%p;
    			if(din[e[i].to]==0)
    			{
    				q.push(e[i].to);
    			}
    		}
    	}
    }
    int main()
    {
    	ll n,m,r,k,u,v,w,sum=0,i;
    	cin>>n>>m>>r>>k;
    	for(i=1;i<=k;i++)
    	{
    		cin>>u>>v>>w;
    		add(u,v,w);
    		dout[u]++;
    		din[0][v]++;
    		din[1][v]++;
    		din[2][v]++;
    		sum=(sum+w)%p;
    	}
    	for(i=1;i<=n;i++)
    	{
    		if(din[0][i]==0)
    		{
    			f[0][i]=1;
    		}
    	}
    	top_sort1(n,din[0],f[0]);
    	for(i=1;i<=n;i++)
    	{
    		if(din[1][i]==0)
    		{
    			f[1][i]=1;
    		}
    	}
    	top_sort2(n,din[1],sum);
    	top_sort1(n,din[2],f[1]);
    	for(i=1;i<=n;i++)
    	{
    		if(dout[i]==0)
    		{
    			cout<<f[1][i]<<" ";
    		}
    	}
    	return 0;
    }
    

总结

  • 开题顺序 T0,T3,T2,T1
  • T2 赛时没有删 freopen ,挂了 25pts
  • T3 用的 gp_hash_table ,空间爆了。
  • T1 写到比赛结束一个多小时也没有调完,很久没有写过大模拟了,该练练了。
    • 菜就多练。
  • T4 看见概率期望就直接跳了,也没时间写了。

后记

  • T0 为原本的 T1 ,因机房人做过的太多所以仅存在了 90s 就被换下去了,赛时只有我交了一份 AC 代码上去。
  • T2 下发了 Special Judge ,还教了怎么使用 Special Judge ,好评。
  • T3 在没有提前说明的情况下使用了捆绑测试。
  • PDF 上写了文件输入输出,但评测时却是标准输入输出。
  • 有大样例,好评。
posted @   hzoi_Shadow  阅读(106)  评论(10编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
扩大
缩小
点击右上角即可分享
微信分享提示