2025省选模拟1

2025省选模拟1

题目来源: 2024省选联测1

T1 HZTG5808. interval 40pts

  • 原题: QOJ 1173. Knowledge Is..

  • 考虑按照左端点升序排序后反悔贪心。

  • 分别维护已经匹配的区间对和未被匹配的区间,若当前区间 a 可以和前面剩余的未被匹配的区间匹配则直接匹配;否则尝试找到一对已经匹配的区间 x,y ,若 y 的右端点比 a 的右端点靠左则替换成 x,a 进行匹配,可以证明将 y 换成 a 扩大了 y 能匹配的区间(如果不换就是 a 的匹配区间),一定不劣。

  • 优先队列按照右端点升序排序即可。

    点击查看代码
    pair<int,int>a[500010];
    priority_queue<int,vector<int>,greater<int> >used,wait;
    int main()
    {
    #define Isaac
    #ifdef Isaac
    	freopen("interval.in","r",stdin);
    	freopen("interval.out","w",stdout);
    #endif
    	int n,ans=0,i;
    	scanf("%d",&n);
    	for(i=1;i<=n;i++)
    	{
    		scanf("%d%d",&a[i].first,&a[i].second);
    	}
    	sort(a+1,a+1+n);
    	for(i=1;i<=n;i++)
    	{
    		if(wait.empty()==0&&wait.top()<a[i].first)
    		{
    			ans++;
    			used.push(a[i].second);
    			wait.pop();
    		}
    		else
    		{
    			if(used.empty()==0&&used.top()<a[i].second)
    			{
    				wait.push(used.top());
    				used.pop();
    				used.push(a[i].second);
    			}
    			else
    			{
    				wait.push(a[i].second);
    			}
    		}
    	}
    	printf("%d\n",ans);	
    	return 0;
    }
    
  • 输出方案时只需要记录下来源后倒着给予编号即可。

    点击查看代码
    struct node
    {
    	int l,r,id;
    }a[500010];
    int col[500010];
    priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >used,wait;
    bool cmp(node a,node b)
    {
    	return (a.l==b.l)?(a.r<b.r):(a.l<b.l);
    }
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("interval.in","r",stdin);
    	freopen("interval.out","w",stdout);
    #endif
    	int n,m,i;
    	scanf("%d%d",&n,&m);
    	for(i=1;i<=n;i++)
    	{
    		scanf("%d%d",&a[i].l,&a[i].r);
    		a[i].id=i;
    	}
    	sort(a+1,a+1+n,cmp);
    	for(i=1;i<=n;i++)
    	{
    		if(wait.empty()==0&&wait.top().first<a[i].l)
    		{
    			col[wait.top().second]=col[a[i].id]=m;
    			m--;
    			used.push(make_pair(a[i].r,a[i].id));
    			wait.pop();
    			if(m==0)
    			{
    				break;
    			}
    		}
    		else
    		{
    			if(used.empty()==0&&used.top().first<a[i].r)
    			{
    				wait.push(used.top());
    				col[a[i].id]=col[used.top().second];
    				col[used.top().second]=0;
    				used.pop();
    				used.push(make_pair(a[i].r,a[i].id));
    			}
    			else
    			{
    				wait.push(make_pair(a[i].r,a[i].id));
    			}
    		}
    	}
    	for(i=1;i<=n;i++)
    	{
    		if(col[i]==0&&m>=1)
    		{
    			col[i]=m;
    			m--;
    		}
    		printf("%d ",col[i]);
    	}
    	return 0;
    }
    
    

T2 HZTG5809. apers 0pts

  • 原题: QOJ 1359. Setting Maps

  • 考虑扩展 k=1 时最小割的做法。

  • 将一个点拆成入点 inx 和出点 out2 ,中间用容量为 cx 的边相连。

  • 对经过地雷数进行分层,相邻两层从 ini,xouti+1,x 连一条容量为 的边表示在 x 放置了地雷(割掉了 ini,xouti,x )。

  • 注意当图不连通时需要输出 0

    点击查看代码
    const ll inf=0x3f3f3f3f3f3f3f3f;
    ll a[210],id[2][10][210],tot=0;
    vector<ll>ans;
    struct MinCut
    {
    	struct node
    	{
    		ll nxt,to,cap,flow;
    	}e[16010];
    	ll head[3010],dis[3010],vis[3010],cur[3010],cnt=1;
    	void add(ll u,ll v,ll w)
    	{
    		cnt++;  e[cnt]=(node){head[u],v,w,0};  head[u]=cnt;
    		cnt++;  e[cnt]=(node){head[v],u,0,0};  head[v]=cnt;
    	}
    	bool bfs(ll s,ll t)
    	{
    		memset(vis,0,sizeof(vis));
    		queue<ll>q;
    		dis[s]=1;  cur[s]=head[s];
    		q.push(s);  vis[s]=1;
    		while(q.empty()==0)
    		{
    			ll x=q.front();  q.pop();
    			for(ll i=head[x];i!=0;i=e[i].nxt)
    			{
    				if(vis[e[i].to]==0&&e[i].cap>e[i].flow)
    				{
    					dis[e[i].to]=dis[x]+1;  cur[e[i].to]=head[e[i].to];
    					q.push(e[i].to);  vis[e[i].to]=1;
    					if(e[i].to==t)  return true;
    				}
    			}
    		}
    		return false;
    	}
    	ll dfs(ll x,ll t,ll flow)
    	{
    		if(x==t)  return flow;
    		ll sum=0,tmp;
    		for(ll i=cur[x];i!=0&&sum<flow;i=e[i].nxt)
    		{
    			cur[x]=i;
    			if(dis[e[i].to]==dis[x]+1&&e[i].cap>e[i].flow)
    			{
    				tmp=dfs(e[i].to,t,min(e[i].cap-e[i].flow,flow-sum));
    				if(tmp==0)  dis[e[i].to]=0;
    				sum+=tmp;
    				e[i].flow+=tmp;  e[i^1].flow-=tmp;
    			}
    		}
    		return sum;
    	}
    	ll Dinic(ll s,ll t)
    	{
    		ll flow=0;
    		while(bfs(s,t)==true)  flow+=dfs(s,t,inf);
    		return flow;
    	}
    }C,D;
    int main()
    {
    #define Isaac
    #ifdef Isaac
    	freopen("apers.in","r",stdin);
    	freopen("apers.out","w",stdout);
    #endif
    	ll n,m,k,u,v,s,t,i,j;
    	cin>>n>>m>>k>>s>>t;
    	for(i=1;i<=k;i++)
    	{
    		for(j=1;j<=n;j++)
    		{
    			tot++;  id[0][i][j]=tot;
    			tot++;  id[1][i][j]=tot;
    		}
    	}
    	for(i=1;i<=n;i++) 
    	{
    		cin>>a[i];
    		for(j=1;j<=k;j++)  
    		{
    			C.add(id[0][j][i],id[1][j][i],a[i]);
    			if(j<=k-1)  C.add(id[0][j][i],id[1][j+1][i],inf);
    		}
    	} 
    	for(i=1;i<=m;i++)
    	{
    		cin>>u>>v;  D.add(u,v,inf);
    		for(j=1;j<=k;j++)  C.add(id[1][j][u],id[0][j][v],inf);
    	}
    	if(D.bfs(s,t)==true&&D.dis[t]<k)  cout<<-1<<endl;
    	else  cout<<C.Dinic(id[0][1][s],id[1][k][t])<<endl;
    	return 0;
    }
    
  • 输出方案同最小割构造。

    点击查看代码
    const ll inf=0x3f3f3f3f3f3f3f3f;
    ll a[210],id[2][10][210],tot=0;
    vector<ll>ans;
    struct MinCut
    {
    	struct node
    	{
    		ll nxt,to,cap,flow;
    	}e[16010];
    	ll head[3010],dis[3010],vis[3010],cur[3010],cnt=1;
    	void add(ll u,ll v,ll w)
    	{
    		cnt++;  e[cnt]=(node){head[u],v,w,0};  head[u]=cnt;
    		cnt++;  e[cnt]=(node){head[v],u,0,0};  head[v]=cnt;
    	}
    	bool bfs(ll s,ll t)
    	{
    		memset(vis,0,sizeof(vis));
    		queue<ll>q;
    		dis[s]=1;  cur[s]=head[s];
    		q.push(s);  vis[s]=1;
    		while(q.empty()==0)
    		{
    			ll x=q.front();  q.pop();
    			for(ll i=head[x];i!=0;i=e[i].nxt)
    			{
    				if(vis[e[i].to]==0&&e[i].cap>e[i].flow)
    				{
    					dis[e[i].to]=dis[x]+1;  cur[e[i].to]=head[e[i].to];
    					q.push(e[i].to);  vis[e[i].to]=1;
    					if(e[i].to==t)  return true;
    				}
    			}
    		}
    		return false;
    	}
    	ll dfs(ll x,ll t,ll flow)
    	{
    		if(x==t)  return flow;
    		ll sum=0,tmp;
    		for(ll i=cur[x];i!=0&&sum<flow;i=e[i].nxt)
    		{
    			cur[x]=i;
    			if(dis[e[i].to]==dis[x]+1&&e[i].cap>e[i].flow)
    			{
    				tmp=dfs(e[i].to,t,min(e[i].cap-e[i].flow,flow-sum));
    				if(tmp==0)  dis[e[i].to]=0;
    				sum+=tmp;
    				e[i].flow+=tmp;  e[i^1].flow-=tmp;
    			}
    		}
    		return sum;
    	}
    	ll Dinic(ll s,ll t)
    	{
    		ll flow=0;
    		while(bfs(s,t)==true)  flow+=dfs(s,t,inf);
    		return flow;
    	}
    }C,D;
    int main()
    {
    // #define Isaac
    #ifdef Isaac
    	freopen("apers.in","r",stdin);
    	freopen("apers.out","w",stdout);
    #endif
    	ll n,m,k,u,v,s,t,i,j;
    	cin>>n>>m>>k>>s>>t;
    	for(i=1;i<=k;i++)
    	{
    		for(j=1;j<=n;j++)
    		{
    			tot++;  id[0][i][j]=tot;
    			tot++;  id[1][i][j]=tot;
    		}
    	}
    	for(i=1;i<=n;i++) 
    	{
    		cin>>a[i];
    		for(j=1;j<=k;j++)  
    		{
    			C.add(id[0][j][i],id[1][j][i],a[i]);
    			if(j<=k-1)  C.add(id[0][j][i],id[1][j+1][i],inf);
    		}
    	} 
    	for(i=1;i<=m;i++)
    	{
    		cin>>u>>v;  D.add(u,v,inf);
    		for(j=1;j<=k;j++)  C.add(id[1][j][u],id[0][j][v],inf);
    	}
    	if(D.bfs(s,t)==true&&D.dis[t]<k)  cout<<-1<<endl;
    	else 
    	{
    		C.Dinic(id[0][1][s],id[1][k][t]);
    		for(i=1;i<=k;i++)
    		{
    			for(j=1;j<=n;j++)
    			{
    				if(C.vis[id[0][i][j]]==1&&C.vis[id[1][i][j]]==0)  ans.push_back(j);
    			}
    		}
    		cout<<ans.size()<<endl;
    		for(i=0;i<ans.size();i++)  cout<<ans[i]<<" ";
    	}
    	return 0;
    }
    

T3 HZTG5810. circles 0pts

  • 原题: QOJ 838. Horrible Cycles

  • 先按照 {a} 升序排序。

  • 观察到最终的环一定是左右部点交错出现。在枚举右部点的过程中,每加入一个左部点与此同时与先前的所有右部点进行连边,可以看做左部点将若干个链连接形成了环。

  • fi,j 表示处理到第 i 个右部点且还需要 j 个左部点进行连接的环的数量。当新加入一个右部点的时候,可以作为一条单独的链加入先前状态集合,有 fi,jfi1,j+(j1)fi1,j1 ,边界为 fi,1fi1,1+1 。接着添加左端点,类似地,有 fi,jfi,j+(j+1)fi,j+1

  • 在更新过程中每个环仅会在最大左部点断开位置处进行计算,但每个环在两个方向上均会对答案产生一次贡献;且每条边产生了一次贡献但不应在最终的答案中,故 12(f0i=1nai) 即为所求。

    点击查看代码
    const ll p=1000000007;
    ll a[5010],f[5010];
    ll qpow(ll a,ll b,ll p)
    {
    	ll ans=1;
    	while(b)
    	{
    		if(b&1)
    		{
    			ans=ans*a%p;
    		}
    		b>>=1;
    		a=a*a%p;
    	}
    	return ans;
    }
    int main()
    {
    #define Isaac
    #ifdef Isaac
    	freopen("circles.in","r",stdin);
    	freopen("circles.out","w",stdout);
    #endif
    	ll n,sum=0,i,j,k;
    	cin>>n;
    	for(i=1;i<=n;i++)
    	{
    		cin>>a[i];
    		sum=(sum+a[i])%p;
    	}
    	sort(a+1,a+1+n);
    	for(i=j=1;i<=n;i++)
    	{
    		for(k=n;k>=2;k--)
    		{
    			f[k]=(f[k]+(k-1)*f[k-1]%p)%p;
    		}
    		f[1]=(f[1]+1)%p;
    		for(;j<=n&&a[j]==i;j++)
    		{
    			for(k=0;k<=n;k++)
    			{
    				f[k]=(f[k]+(k+1)*f[k+1]%p)%p;
    			}
    		}
    	}
    	cout<<(f[0]-sum+p)%p*qpow(2,p-2,p)%p<<endl;
    	return 0;
    }
    

总结

  • 整场都在罚坐。
posted @   hzoi_Shadow  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探
扩大
缩小
点击右上角即可分享
微信分享提示