题目:https://loj.ac/problem/2977

想到斯坦纳树。但以为只能做 “包含一些点” 而不是 “包含一些颜色” 。而且不太会处理中位数。

其实 “包含一些颜色” 用斯坦纳树做也和普通的一模一样……只是赋初值的时候,遇到该颜色的点就可以更新一下罢了……

中位数可以二分。每个点除了 “块数” 这个关键字之外,再带一个关键字表示 “a[ ][ ]是否大于二分值” ,用 -1 表示不大于,1表示大于,然后普通地跑一个斯坦纳树,看看第二关键字那一维是否 <= 0 即可。

至于处理 “从 m 个颜色中选 k 个颜色 ”,可以用随机化的算法!就是每次给每种颜色一个 0~k-1 的映射,然后直接求 “ 0~k-1 都出现 ” 的答案即可。同一种颜色会映射到同一种颜色,所以映射后的 k 种不同颜色,在映射前也是 k 种不同颜色。

相当于把颜色分成 k 组,要求每组选至少一种颜色。要随机多分几遍组才行。据说 100 次之后正确率就很高了。

一开始求了两点间距离,然后做斯坦纳树的时候,一个点把所有点都用那个距离更新一遍。非常慢。

不用求两点间距离,做斯坦纳树,更新的时候只更新四相邻的格子即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<queue>
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
int Mn(int a,int b){return a<b?a:b;}
const int N=,INF=1e6+,K=(<<)+;
int n,m,k,tot,bh[N][N],dy[N][],c[N],a[N],tp[N],R;
int bin[],tp2[N],cb[N],ans,prn; bool vis[N];
int xx[]={-,,,},yy[]={,-,,};
struct Node{
int x,y;
Node(int x=,int y=):x(x),y(y) {}
void init(){x=y=N;}
bool operator< (const Node &b)const
{return x==b.x?y<b.y:x<b.x;}
Node operator+ (const Node &b)const
{return Node(x+b.x,y+b.y);}
Node operator- (const Node &b)const
{return Node(x-b.x,y-b.y);}
}vl[N],dp[N][K];
priority_queue<pair<Node,int> >q;
queue<int> q2;
Node Mn(Node u,Node v){return u<v?u:v;}
Node Inv(Node u){return Node(-u.x,-u.y);}
void init()
{
ans=N; prn=INF;
bin[]=;for(int i=;i<=k;i++)bin[i]=bin[i-]<<;
for(int i=;i<=tot;i++)tp[i]=a[i];
sort(tp+,tp+tot+); R=unique(tp+,tp+tot+)-tp-;
}
Node chk(int mid)
{
for(int i=;i<=tot;i++)vl[i]=Node(,a[i]<=mid?-:);
for(int i=;i<=tot;i++)
{
for(int j=;j<bin[k];j++)dp[i][j].init();
if(c[i]!=-)dp[i][bin[cb[i]]]=vl[i];//if
}
for(int s=;s<bin[k];s++)
{
for(int i=;i<=tot;i++)
for(int t=(s-)&s;t;t=(t-)&s)
dp[i][s]=Mn(dp[i][s],dp[i][t]+dp[i][s^t]-vl[i]);
for(int i=;i<=tot;i++)q2.push(i),vis[i]=;
while(q2.size())
{
int k=q2.front(); q2.pop(); vis[k]=;
int x=dy[k][], y=dy[k][];
for(int i=,tx,ty;i<;i++)
{
tx=x+xx[i]; ty=y+yy[i];
if(!tx||tx>n||!ty||ty>m)continue;
int v=bh[tx][ty]; if(c[v]==-)continue;
if(dp[k][s]+vl[v]<dp[v][s])
{
dp[v][s]=dp[k][s]+vl[v];
if(!vis[v])q2.push(v),vis[v]=;
}
}
}
} int U=bin[k]-; Node ret=dp[][U];
for(int i=;i<=tot;i++)ret=Mn(ret,dp[i][U]);
return ret;
}
void solve()
{
for(int i=;i<=tot;i++) tp2[i]=rand()%k;
for(int i=;i<=tot;i++) cb[i]=tp2[c[i]];
int l=,r=R,ret=N,r2=N;
while(l<=r)
{
int mid=l+r>>;
Node d=chk(tp[mid]); ret=d.x;
if(ret==N||ret>ans)break;//
if(d.y<=)r2=tp[mid],r=mid-;
else l=mid+;
}
if(ret<ans)ans=ret,prn=r2;
else if(ret==ans)prn=Mn(prn,r2);
}
int main()
{
int T=rdn(); srand(time());
while(T--)
{
n=rdn();m=rdn();k=rdn(); tot=;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
bh[i][j]=++tot,dy[tot][]=i,dy[tot][]=j;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)c[bh[i][j]]=rdn();
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)a[bh[i][j]]=rdn();
init();
for(int t=;t<=;t++)solve();
if(ans==N)puts("-1 -1");
else printf("%d %d\n",ans,prn);
}
return ;
}

LOJ 2997 「THUSCH 2017」巧克力——思路+随机化+斯坦纳树的更多相关文章

  1. @loj - 2977@ 「THUSCH 2017」巧克力

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 「人生就像一盒巧克力,你永远不知道吃到的下一块是什么味道.」 明 ...

  2. LOJ#2977. 「THUSCH 2017」巧克力(斯坦纳树+随机化)

    题目 题目 做法 考虑部分数据(颜色较少)的: 二分中位数\(mid\),将\(v[i]=1000+(v[i]>mid)\) 具体二分操作:然后求出包含\(K\)种颜色的联通快最小的权值和,判断 ...

  3. LOJ 2979 「THUSCH 2017」换桌——多路增广费用流

    题目:https://loj.ac/problem/2979 原来的思路: 优化连边.一看就是同一个桌子相邻座位之间连边.相邻桌子对应座位之间连边. 每个座位向它所属的桌子连边.然后每个人建一个点,向 ...

  4. LOJ #2978「THUSCH 2017」杜老师

    听说LOJ传了THUSC题赶紧上去看一波 随便点了一题都不会做想了好久才会写暴力爆了一发过了... LOJ #2978 题意 $ T$次询问,每次询问$ L,R$,问有多少种选取区间中数的方案使得选出 ...

  5. LOJ 2980 「THUSCH 2017」大魔法师——线段树

    题目:https://loj.ac/problem/2980 线段树维护矩阵. 然后是 30 分.似乎是被卡常了?…… #include<cstdio> #include<cstri ...

  6. LOJ 2978 「THUSCH 2017」杜老师——bitset+线性基+结论

    题目:https://loj.ac/problem/2978 题解:https://www.cnblogs.com/Paul-Guderian/p/10248782.html 第 i 个数的 bits ...

  7. loj#2978. 「THUSCH 2017」杜老师(乱搞)

    题面 传送门 题解 感谢yx巨巨 如果一个数是完全平方数,那么它的所有质因子个数都是偶数 我们把每一个数分别维护它的每一个质因子的奇偶性,那么就是要我们选出若干个数使得所有质因子的个数为偶数.如果用线 ...

  8. 「THUSCH 2017」大魔法师 解题报告

    「THUSCH 2017」大魔法师 狗体面太长,帖链接了 思路,维护一个\(1\times 4\)的答案向量表示\(A,B,C,len\),最后一个表示线段树上区间长度,然后每次的操作都有一个转移矩阵 ...

  9. LOJ 2288「THUWC 2017」大葱的神力

    LOJ 2288「THUWC 2017」大葱的神力 Link Solution 比较水的提交答案题了吧 第一个点爆搜 第二个点爆搜+剪枝,我的剪枝就是先算出 \(mx[i]\) 表示选取第 \(i \ ...

随机推荐

  1. JS中$含义及用法

    $在JS中本身只是一个符号而异,在JS里什么也不是.但在JS应用库JQUERY的作者将之做为一个自定义函数名了,这个函数是获取指定网页元素的函数,使用非常之频繁,所以好多新手不知道,还以为$是JS的什 ...

  2. Python算法每日一题--002--求众数

    给定一个大小为 n 的数组,找到其中的众数.众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素. 你可以假设数组是非空的,并且给定的数组总是存在众数. 示例 1: 输入: [3,2,3]输出: 3示 ...

  3. workflow-core 简介

    最近想做一个OA相关的网站开发,一直都听说有workflow的东西,之前也断断续续学习过 Workflow Foundation 4.0,还是没有搞明白到底能够用它做什么 但还是觉得workflow在 ...

  4. Java单链表

    一.概述 二.主方法 //创建头结点 private HeroNode head = new HeroNode(-1,null,null); //计数器,用于id的自增 private static ...

  5. [CF960G]Bandit Blues(第一类斯特林数+分治卷积)

    Solution: ​ 先考虑前缀,设 \(f(i, j)\) 为长度为 \(i\) 的排列中满足前缀最大值为自己的数有 \(j\) 个的排列数. 假设新加一个数 \(i+1\) 那么会有: \[ f ...

  6. Vue的入门之安装

    vue.js是前端框架中比较热门的,因为工作关系,也加入了浩浩荡荡的学习大潮中,用笔记记录下点滴,便于后面学习查阅! 1 node.js环境的安装包(npm包管理器) 2 vue-cli 脚手架构建工 ...

  7. codeforces hack

    对某一题,首先你自己要先过TEST. 然后回到比赛的PROBLEM列表,把这题后面的锁锁上(锁上了就不能再提交了,所以没把握就别锁了), 然后到ROOM里面,你就可以看别人代码了,下面有HACK按钮, ...

  8. APM-全链路追踪

    1.故障快速定位 跨语言实现开发中在业务日志中添加调用链ID,可以通过调用链结合业务日志快速定位错误信息. 2.各个调用环节的性能分析 分析调用链的各个环节耗时,分析系统的性能瓶颈,找到系统的薄弱环节 ...

  9. elasticsearch 基础 —— Inner hits

    Inner hits The parent-join and nested 功能允许返回具有不同范围匹配的文档.在父/子案例中,基于子文档中的匹配返回父文档,或者基于父文档中的匹配返回子文档.在嵌套的 ...

  10. gcc版本切换

    查看安装的gcc版本 sudo update--alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 100 显示所有版本gcc路径 sudo ...