2024初三集训模拟测试4

2024初三集训模拟测试4

\(T1\) 打赌 \(0pts\)

  • 模拟即可。

    点击查看代码
    int main()
    {
    	freopen("pogodak.in","r",stdin);
    	freopen("pogodak.out","w",stdout);
    	ll n,m,ans=0,u=1,d=6,f=2,b=5,l=4,r=3,lsu,lsd,lsf,lsb,lsl,lsr,i,j;
    	cin>>n>>m;
    	for(i=1;i<=n;i++)
    	{
    		if(i%2==1)
    		{
    			ans+=m/4*(u+d+l+r);            
    			for(j=1;j<=m%4;j++)
    			{
    				if(j!=1)
    				{
    					lsu=u;
    					lsd=d;
    					lsl=l;
    					lsr=r;
    					u=lsl;
    					d=lsr;
    					l=lsd;
    					r=lsu;
    				}
    				ans+=u;
    			}
    			lsu=u;
    			lsd=d;
    			lsf=f;
    			lsb=b;
    			u=lsb;
    			d=lsf;
    			f=lsu;
    			b=lsd;
    		}
    		else
    		{
    			ans+=m/4*(u+d+l+r);
    			for(j=1;j<=m%4;j++)
    			{
    				if(j!=1)
    				{
    					lsu=u;
    					lsd=d;
    					lsl=l;
    					lsr=r;
    					u=lsr;
    					d=lsl;
    					l=lsu;
    					r=lsd;
    				}
    				ans+=u;
    			}
    			lsu=u;
    			lsd=d;
    			lsf=f;
    			lsb=b;
    			u=lsb;
    			d=lsf;
    			f=lsu;
    			b=lsd;
    		}
    	}
    	cout<<ans<<endl;
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

\(T2\) 舞会 \(0pts\)

  • 从贪心角度的分析,将正整数的男孩与负整数的女孩进行配对,负整数的男孩与正整数的女孩进行配对时,要尽可能地选择接近的数。排序后使用双指针维护即可。

    点击查看代码
    ll a[2][200000],b[2][200000];
    int main()
    {
    	freopen("party.in","r",stdin);
    	freopen("party.out","w",stdout);
    	ll n,x,n1=0,n2=0,n3=0,n4=0,ans=0,l,r,i;
    	cin>>n;
    	for(i=1;i<=n;i++)
    	{
    		cin>>x;
    		if(x<0)
    		{
    			n1++;
    			a[0][n1]=-x;
    		}
    		else
    		{
    			n2++;
    			a[1][n2]=x;
    		}
    	}
    	for(i=1;i<=n;i++)
    	{
    		cin>>x;
    		if(x<0)
    		{
    			n3++;
    			b[0][n3]=-x;
    		}
    		else
    		{
    			n4++;
    			b[1][n4]=x;
    		}
    	}
    	sort(a[0]+1,a[0]+1+n1);
    	sort(a[1]+1,a[1]+1+n2);
    	sort(b[0]+1,b[0]+1+n3);
    	sort(b[1]+1,b[1]+1+n4);
    	for(l=1,r=1;l<=n1&&r<=n4;l++,r++)
    	{
    		while(l<=n1&&a[0][l]<=b[1][r])
    		{
    			l++;
    		}
    		ans+=(l<=n1);
    	}
    	for(l=1,r=1;l<=n2&&r<=n3;l++,r++)
    	{
    		while(r<=n3&&a[1][l]>=b[0][r])
    		{
    			r++;
    		}
    		ans+=(r<=n3);
    	}
    	cout<<ans<<endl;
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

\(T3\) 最小生成树 \(0pts\)

  • 经打表,有最小生成树的边权和为 \(n-1\) ,构造每条边上的两端点互质即可。

  • \(\prod\limits_{i=1}^{n}\varphi(i)\) 即为所求。

    点击查看代码
    const ll p=100000007;
    ll phi[40000],prime[40000],vis[40000],len=0;
    void euler(ll n)
    {
    	memset(vis,0,sizeof(vis));
    	phi[1]=1;
    	for(ll i=2;i<=n;i++)
    	{
    		if(vis[i]==false)
    		{
    			len++;
    			prime[len]=i;
    			phi[i]=i-1;
    		}
    		for(ll j=1;j<=len&&i*prime[j]<=n;j++)
    		{
    			vis[i*prime[j]]=1;
    			if(i%prime[j]==0)
    			{
    				phi[i*prime[j]]=phi[i]*prime[j];
    				break;
    			}
    			else
    			{
    				phi[i*prime[j]]=phi[i]*(prime[j]-1);
    			}
    		}
    	}
    }
    int main()
    {
    	freopen("mst.in","r",stdin);
    	freopen("mst.out","w",stdout);
    	ll n,ans=1,i;
    	cin>>n;
    	euler(n);
    	for(i=1;i<=n;i++)
    	{
    		ans=ans*phi[i]%p;
    	}
    	cout<<ans<<endl;
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

\(T4\) 买汽水 \(100pts\)

  • 原题: [ABC184F] Programming Contest

  • 部分分

    • \(50pts\)
      • 超大背包,暴力 \(DFS\) 枚举每天买或不买饮料。

      • 时间复杂度为 \(O(2^{n})\)

        点击查看代码
        ll p[50],ans=0;
        void dfs(ll x,ll n,ll m,ll worth)
        {
        	if(x==n+1)
        	{
        		if(worth<=m)
        		{
        			ans=max(ans,worth);
        		}
        	}
        	else
        	{
        		if(worth+p[x]<=m)
        		{
        			dfs(x+1,n,m,worth+p[x],worth+p[x]);
        		}
        		dfs(x+1,n,m,worth);
        	}
        }
        int main()
        {
        	freopen("drink.in","r",stdin);
        	freopen("drink.out","w",stdout);
        	ll n,m,i;
        	cin>>n>>m;
        	for(i=1;i<=n;i++)
        	{
        		cin>>p[i];
        	}
        	dfs(1,n,m,0);
        	cout<<ans<<endl;
        	fclose(stdin);
        	fclose(stdout);
        	return 0;
        }
        
    • \(60pts\) :输出 \(m\)
  • 正解

    • 考虑优化搜索过程,使用双向搜索。具体地,对于 \([1,\left\lfloor \frac{n}{2}\right\rfloor]\) 进行第一遍搜索,对于得到的价值存到一个 set 里面。对于 \([\left\lfloor \frac{n}{2}\right\rfloor+1,n]\) 进行第二遍搜索,对于得到的价值在 set 里面找到满足 \(\le m-\) 当前重量的最大价值,进行转移即可。
    • 时间复杂度为 \(O(2^{\frac{n}{2}}n)\)
    点击查看代码
    set<ll>vis;
    ll p[50],ans=0;
    void dfsl(ll x,ll n,ll m,ll worth)
    {
    	if(x==n+1)
    	{
    		if(worth<=m)
    		{
    			vis.insert(worth);
    		}
    	}
    	else
    	{
    		if(worth+p[x]<=m)
    		{
    			dfsl(x+1,n,m,worth+p[x]);
    		}
    		dfsl(x+1,n,m,worth);
    	}
    }
    void dfsr(ll x,ll n,ll m,ll worth)
    {
    	if(x==n+1)
    	{
    		if(worth<=m)
    		{
    			ans=max(ans,worth+(*(--vis.upper_bound(m-worth))));
    		}
    	}
    	else
    	{
    		if(worth+p[x]<=m)
    		{
    			dfsr(x+1,n,m,worth+p[x]);
    		}
    		dfsr(x+1,n,m,worth);
    	}
    }
    int main()
    {
    	freopen("drink.in","r",stdin);
    	freopen("drink.out","w",stdout);
    	ll n,m,i;
    	cin>>n>>m;
    	for(i=1;i<=n;i++)
    	{
    		cin>>p[i];
    	}
    	dfsl(1,n/2,m,0);
    	dfsr(n/2+1,n,m,0);
    	cout<<ans<<endl;
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

总结

  • 开题顺序 \(T4,T2,T1\)
  • 要善于从题目背景中获得信息。
posted @ 2024-02-22 15:42  hzoi_Shadow  阅读(49)  评论(5编辑  收藏  举报
扩大
缩小
/*
*/