• [提高组互测] Day5


    总结

    这次没有挂分,不过还是被淡随切吊打了

    任何题最基本的问题转化都要有,思维步骤都有共通之处,不要只会做序列题啊

    把题想简单一点,相信自己的实力都可以切,毕竟我切过 (3400) 的题啊!

    保留环节:感谢 ( t crashed) 大佬的精心准备,虽然他的电脑因为蓝屏必须重新造数据

    [CCO 2019] Sirtet

    题目描述

    点此看题

    解法

    ( t naive) 的题意转化:我们求出每个点的下落距离就可以知道最终状态。

    对于初始四联通的点集,我们把他们连接起来当作一个整体,那么它们的下落距离是相同的。

    考虑对于每个有物体的格子找到它下面第一个物品,设它的颜色是 (x)(每个点集颜色相同):

    • 如果颜色相同,那么可以忽略。
    • 如果不存在这样一个物品,那么 $d_xleq $ 到底部的距离。
    • 如果存在这样一个物品,设其颜色是 (y),那么 (d_xleq d_y+) 它们的距离。

    显然是一个差分约束问题,建出来图之后直接跑即可,比省选的那道差分约束板多了

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    using namespace std;
    const int M = 1000005;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,k,a[M],b[M],c[M],tot,f[M];char s[M];
    int dis[M],ans[M];
    int id(int x,int y) {return m*(x-1)+y;}
    struct edge
    {
    	int v,c,next;
    }e[2*M];
    struct node
    {
    	int u,c;
    	bool operator < (const node &b) const
    	{
    		return c>b.c;
    	}
    };priority_queue<node> q;
    void dfs(int x,int y)
    {
    	if(!a[id(x,y)] || b[id(x,y)]) return ;
    	b[id(x,y)]=k;
    	if(x>1) dfs(x-1,y);
    	if(x<n) dfs(x+1,y);
    	if(y>1) dfs(x,y-1);
    	if(y<m) dfs(x,y+1);
    }
    void add(int u,int v,int c)
    {
    	e[++tot]=edge{v,c,f[u]},f[u]=tot;
    }
    void dijkstra()
    {
    	dis[k+1]=0;
    	q.push(node{k+1,0});
    	while(!q.empty())
    	{
    		int u=q.top().u;
    		int w=q.top().c;q.pop();
    		if(dis[u]<w) continue;
    		for(int i=f[u];i;i=e[i].next)
    		{
    			int v=e[i].v,c=e[i].c;
    			if(dis[v]>dis[u]+c)
    			{
    				dis[v]=dis[u]+c;
    				q.push(node{v,dis[v]});
    			}
    		}
    	}
    }
    int main()
    {
    	//freopen("tpt.in","r",stdin);
    	//freopen("tpt.out","w",stdout);
    	n=read();m=read();
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%s",s+1);
    		for(int j=1;j<=m;j++)
    			a[id(i,j)]=(s[j]=='#');
    	}
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			if(a[id(i,j)] && !b[id(i,j)])
    				k++,dfs(i,j);
    	memset(dis,0x3f,sizeof dis);
    	for(int i=n;i>=1;i--)
    		for(int j=1;j<=m;j++) if(a[id(i,j)])
    		{
    			int w=b[id(i,j)],p=id(c[j],j);
    			if(!c[j])//nothing down below
    				add(k+1,w,n-i);
    			else if(b[p]!=w)//not the same color
    				add(b[p],w,c[j]-i-1);
    			c[j]=i;
    		}
    	dijkstra();
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    		{
    			int x=id(i,j);
    			if(a[x]) ans[id(i+dis[b[x]],j)]=a[x];
    		}
    	for(int i=1;i<=n;i++,puts(""))
    		for(int j=1;j<=m;j++)
    		{
    			if(ans[id(i,j)]) putchar('#');
    			else putchar('.');
    		}
    }
    

    「ROI 2019 Day2」课桌

    题目描述

    点此看题

    解法

    这道题的结论很多都是感受出来得分,不给证明,现在对追求严谨的我真是一种煎熬啊

    结论1:将学生按升高排序之后相邻两个配对最优。

    结论2:把课桌升序排序之后按顺序分给学生最优。这里稍微解释一下,首先我们要除去课桌有包含的情况,那么按左端点排序之后满足左端点单增,右端点单增,这样就能区分顺序了。

    那么直接把 (m) 组的相邻学生绑定起来称为一块,那么一共有 (n) 块学生,对于每一块可以单独做,计算每个课桌的代价时可以搞一个双指针,时间复杂度 (O(nm+mk))

    复杂度爆炸的原因是把每一块学生割裂开来了,利用第二个性质,每一块学生对应的最优决策点是单调不降的。这时候可以无脑上决策单调性分治了,每次求第 (mid) 块的最优匹配点,然后左右的决策点范围是 ([ql,mid])([mid,qr]),时间复杂度 (O((k+nm)log m))

    #include <cstdio>
    #include <vector>
    #include <algorithm>
    using namespace std;
    const int M = 400005;
    #define int long long
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,k,ans,b[M];vector<int> a[M];
    struct node
    {
    	int l,r;
    	bool operator < (const node &b) const
    	{
    		return l<b.l;
    	}
    }s[M];
    void cdq(int l,int r,int ql,int qr)
    {
    	if(l>r) return ;
    	int x=(l+r)>>1;
    	int pre=0,suf=0,j=0,k=0,res=1e15,mid=ql;
    	int len=a[x].size(),nl=0,nr=len;
    	for(auto y:a[x]) suf+=y;
    	for(int i=ql;i<=qr;i++)
    	{
    		if(s[i].r<=s[i-1].r) continue;//useless
    		while(j<len && a[x][j]<=s[i].l)
    		{
    			pre+=a[x][j];
    			j++;nl++;
    		}
    		while(k<len && a[x][k]<s[i].r)
    		{
    			suf-=a[x][k];
    			k++;nr--;
    		}
    		int tmp=(suf-s[i].r*nr)+(s[i].l*nl-pre);
    		if(tmp<res) mid=i,res=tmp;
    	}
    	ans+=res;
    	cdq(l,x-1,ql,mid);
    	cdq(x+1,r,mid,qr);
    }
    signed main()
    {
    	m=read();n=read();k=read();
    	for(int i=1;i<=k;i++)
    		s[i].l=read(),s[i].r=read();
    	sort(s+1,s+1+k);
    	for(int i=1;i<=m;i++)
    	{
    		for(int j=1;j<=2*n;j++)
    			b[j]=read();
    		sort(b+1,b+1+2*n);
    		for(int j=1;j<=n;j++)
    		{
    			a[j].push_back(b[2*j-1]);
    			a[j].push_back(b[2*j]);
    		}
    	}
    	for(int i=1;i<=n;i++)
    		sort(a[i].begin(),a[i].end());
    	cdq(1,n,1,k);
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    Solon 1.6.25 发布,轻量级应用开发框架
    Solon 1.6.21 发布,轻量级应用开发框架
    Solon Web 开发,十四、与Spring、Jsr330的常用注解对比
    Solon 1.6.33 发布,更现代感的应用开发框架
    QA: Solon 出现中文乱码怎么办?
    QA: Solon 怎么输出下载文件流?
    Solon 1.6.29 发布,轻量级应用开发框架
    Solon 1.6.18 发布,轻量级应用开发框架
    Solon 1.6.30 发布,更现代感的应用开发框架
    Water 2.5 发布,一站式服务治理平台
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15411864.html
Copyright © 2020-2023  润新知