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 \%\) :由于 \(\frac{n}{k}\) 为偶数,故在待选递增序列中左右端各依次取 \(\frac{n}{2k}\) 个数即可。

      点击查看代码
      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=k \ne 1\)\(\frac{n(n+1)}{2} \not\equiv 0 \pmod{k}\) 时,无解。
    • \(k=1\) 时,依次输出 \(1 \sim n\) 即可。
    • \(\frac{n}{k}\) 为偶数时,在待选递增序列中左右端各依次取 \(\frac{n}{2k}\) 个数即可。
    • \(\frac{n}{k}\) 为奇数时,考虑尽可能减少因 \(\frac{n}{k}\) 为奇数而对答案产生的影响,这就要求我们尽可能缩小 \(\frac{n}{k}\) 的范围。为方便代码书写,我们选择每个子集中特殊构造 \(3\) 个数,剩下的 \(\frac{n}{k}-3\) 个数处理方式同 \(\frac{n}{k}\) 为偶数时的构造方式。具体地,我们单独选出 \(1 \sim 3k\) 来进行特殊构造。此时问题转化为了 \(3k\) 个连续的自然数如何将其分为 \(k\) 组,每组恰好只有 \(3\) 个数,且每组内数的总和相等。其中一种构造方式为 \(\begin{cases} (1 \le i \le \frac{k-1}{2} ): i+(\frac{3k+1}{2}+i)+(3k+1-2i)=\frac{3(3k+1)}{2} \\ (\frac{k+1}{2} \le i \le k): i+(\frac{k+1}{2}+i)+(4k+1-2i)=\frac{3(3k+1)}{2} \end{cases}\)
    点击查看代码
    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\)
      • 在线做法

        • 询问的本质是对之前的所有修改操作进行修改,找到第一个所得高度 \(\ge y\) 的位置的时间,若没有找到则为 \(0\)
        • 枚举并统计之前的所有修改操作对当前查询的影响即可。
        • 最坏时间复杂度为 \(O(q^2)\) ,带 \(\frac{1}{4}\) 的常数。
        点击查看代码
        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;
        }
        
  • 正解
    • 离线做法
      • 考虑优化暴力的在线做法。将所有操作进行离线下来,同样统计之前的所有修改操作对当前查询的影响。
        • 二分树状数组
          • 树状数组记录每个点每个时刻的高度,然后二分即可。用扫描线的思想将二维树状数组压成一维数组。具体地,对于一段修改的区间 \([l_{i},r_{i}]\) ,当扫描到 \(l\) 时,在 \(l\) 位置上加上 \(h_{i}\) ,增加影响;当扫描到 \(r+1\) 时,在 \(r+1\) 位置上减去 \(h_{i}\) ,消除影响。

            点击查看代码
            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\)
  • 正解

    • \(f_{i}\) 表示在不考虑堵塞情况下,经过 \(i\) 点的污水总吨数。
    • 由于若 \((x,y)\) 堵塞,经过 \(x\) 点经过的污水总吨数不变,故当 \((x,y)\) 堵塞时,经过 \(y\) 点的污水总吨数减少了 \(\frac{f_{x}}{dout_{x}}\) ,经过 \(x\) 点的其他子节点的污水总吨数增加了 \(\frac{f_{x}}{dout_{x}-1} - \frac{f_{x}}{dout_{x}}= \frac{f_{x}}{dout_{x}(dout_{x}-1)}\) 。将 \(-\frac{f_{x}}{dout_{x}}\)\(\frac{f_{x}}{dout_{x}(dout_{x}-1)}\) 放在原图上,计算出原始期望总吨数,可以得到新的 \(f\)
    • 但枚举 \(x\) 点的其他子节点时间复杂度会爆炸,但 \(x\) 点的其他子节点每个增加 \(\frac{f_{x}}{dout_{x}(dout_{x}-1)}\) 可以转化为从 \(x\) 点增加 \(\frac{f_{x}}{dout_{x}(dout_{x}-1)} \times dout_{x}=\frac{f_{x}}{dout_{x}-1}\)\(y\) 点减少了 \(\frac{f_{x}}{dout_{x}}+\frac{f_{x}}{dout_{x}(dout_{x}-1)}=\frac{f_{x}}{dout_{x}-1}\) ,然后再转移到 \(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 @ 2024-02-19 21:40  hzoi_Shadow  阅读(72)  评论(9编辑  收藏  举报
扩大
缩小
/*
*/