%%%神仙题。

居然是图论,我还一直以为是二分图或者啥数据结构。

直接说正解了,将数看作节点,牌看做边,从牌的正面的数想反面连边权为1的边,反面向正面连边权为0的边(注意用到成对存储的技巧,之后会非常巧妙地用到),可以发现就是要求反转几条边可以使每个点的出读小于等于1。那么每个联通图只可能是树或基环树。可以先dfs判断求出每个联通图的点数np和边数ne,若ne/2(双向边)>np,那么这个联通图不合法直接输出-1 -1即可。

 void dfs(int x,int fa)
{
vi[x]=;np++;
for(int i=f(x);i;i=n(i))
{
ne++;
if(v(i)!=fa)
if(!vi[v(i)])dfs(v(i),x);
}
}
bool pd()
{
for(int i=;i<=n*;i++)
if(!vi[i])
{
np=ne=,dfs(i,);
if(np<ne/)return ;
}
return ;
}

代码实现

接下来考虑他是树的情况:

对于确定的跟节点,翻转的边的个数就是将所有点指向父亲节点(可以动手画一下),可以用树形dp求得。但是要枚举根节点吗?其实可以用到二次扫描和换根法,设以x为根要反转的边数为f[x],那么其实f[son]可以用f[x]更新:如果x->son的边权为1,则f[son]=f[x]-1,否则f[son]=f[x]+1.这样我们就解决了树的情况。

 int f[MAXN],st,en,ned;
void dfs1(int x,int fa)
{
v[x]=;f[x]=;
for(int i=f(x);i;i=n(i))
if(v(i)!=fa)
{
if(!v[v(i)])
{
dfs1(v(i),x);
f[x]+=f[v(i)]+w(i);
}
else st=u(i),en=v(i),ned=i;
}
}
int f2[MAXN];
vector<int> tem;
void dfs2(int x,int fa)
{
tem.push_back(f2[x]);
for(int i=f(x);i;i=n(i))
if(v(i)!=fa && i!=ned && i!=(ned^))
{
if(w(i))f2[v(i)]=f2[x]-;
else f2[v(i)]=f2[x]+;
dfs2(v(i),x);
}
}

代码实现

下面看基环树:

在dfs时找出环上的随机一条边记录,将它去掉按树处理,最后在考虑这条边的影响。那么边的成对储存就有用了,将边的编号%2就是它从u指向v的权值。

                 ned%=;
if(f2[st]+ned==f2[en]+(ned^))minn=;
else minn=;
ans+=min(f2[st]+ned,f2[en]+(ned^));

代码实现

 #include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#define MAXN 200010
#define mod 998244353
#define LL long long
#define int LL
#define ma(x) memset(x,0,sizeof(x))
using namespace std;
struct edge
{
int u,v,w,nxt;
#define u(x) ed[x].u
#define v(x) ed[x].v
#define w(x) ed[x].w
#define n(x) ed[x].nxt
}ed[MAXN*];
int first[MAXN],num_e=;
#define f(x) first[x]
int T,n; int np,ne;
bool v[MAXN],vi[MAXN];
void dfs(int x,int fa)
{
vi[x]=;np++;
for(int i=f(x);i;i=n(i))
{
ne++;
if(v(i)!=fa)
if(!vi[v(i)])dfs(v(i),x);
}
}
bool pd()
{
for(int i=;i<=n*;i++)
if(!vi[i])
{
np=ne=,dfs(i,);
if(np<ne/)return ;
}
return ;
}
int f[MAXN],st,en,ned;
void dfs1(int x,int fa)
{
v[x]=;f[x]=;
for(int i=f(x);i;i=n(i))
if(v(i)!=fa)
{
if(!v[v(i)])
{
dfs1(v(i),x);
f[x]+=f[v(i)]+w(i);
}
else st=u(i),en=v(i),ned=i;
}
}
int f2[MAXN];
vector<int> tem;
void dfs2(int x,int fa)
{
// v[x]=1;
tem.push_back(f2[x]);
for(int i=f(x);i;i=n(i))
if(v(i)!=fa && i!=ned && i!=(ned^))
{
if(w(i))f2[v(i)]=f2[x]-;
else f2[v(i)]=f2[x]+;
// if(!v[v(i)])
dfs2(v(i),x);
}
}
inline void add(int u,int v,int w);
signed main()
{
// freopen("back5.in","r",stdin);
// freopen("1.out","w",stdout); cin>>T;
while(T--)
{
ma(f);ma(f2);ma(v);ma(vi);ma(first);num_e=;tem.clear();
scanf("%lld",&n);
int a,b;
for(int i=;i<=n;i++)
{
scanf("%lld%lld",&a,&b);
add(a,b,);add(b,a,);
}
if(pd()){puts("-1 -1");continue;}
int minn=,ans=,ans2=;
for(int i=;i<=n*;i++)
if(!v[i])
{
st=en=ned=-;tem.clear();minn=;
dfs1(i,);
f2[i]=f[i];
dfs2(i,);
if(st==-)
{
sort(tem.begin(),tem.end());
for(int j=;j<tem.size();j++)
if(tem[j]==tem[])minn++;
else break;
ans+=tem[];
}
else
{
ned%=;
if(f2[st]+ned==f2[en]+(ned^))minn=;
else minn=;
ans+=min(f2[st]+ned,f2[en]+(ned^));
}
ans2=(ans2*minn)%mod;
}
printf("%lld %lld\n",ans,ans2);
}
}
inline void add(int u,int v,int w)
{
++num_e;
u(num_e)=u;
v(num_e)=v;
w(num_e)=w;
n(num_e)=f(u);
f(u)=num_e;
}

完整代码

[***]HZOJ 哪一天她能重回我身边的更多相关文章

  1. Noip模拟77 2021.10.15

    T1 最大或 $T1$因为没有开$1ll$右移给炸掉了,调了一年不知道为啥,最后实在不懂了 换成$pow$就过掉了,但是考场上这题耽误了太多时间,后面的题也就没办法好好打了.... 以后一定要注意右移 ...

  2. $dy$讲课总结

    字符串: 1.广义后缀自动机(大小为\(m\))上跑一个长度为\(n\)的串,所有匹配位置及在\(parent\)树上其祖先的数量的和为\(min(n^2,m)\),单次最劣是\(O(m)\). 但是 ...

  3. 重回博客 谈一谈Node中的异步和单线程

    重回博客,这个帐号之前注册后就只发了一篇博客.听朋友建议,决定一周两次更新. 第一篇谈论一下最近想的比较多的异步的问题. 传统多线程异步 传统的异步是多线程的,当要同时做两件事的时候,他们是执行在不同 ...

  4. Python之父重回决策层

    在Guido van Rossum(吉多·范罗苏姆)卸任BDFL(“终身仁慈独裁者”)一职半年多之后,Python社区迎来了新的治理新方案:指导委员会模式,而经过投票Guido van Rossum也 ...

  5. Python之父重回决策层,社区未来如何发展?

    春节假期结束了,大家陆续地重回到原来的生活轨道上.假期是一个很好的休息与调节的机会,同时,春节还有辞旧迎新的本意,它是新的轮回的开端. 在 Python 社区里,刚发生了一件大事,同样有开启新纪元的意 ...

  6. 《重回耶路撒冷——犹太人的三千年》(Return to Jerusalem)读后感

    写在前面 书名:<重回耶路撒冷——犹太人的三千年>(Return to Jerusalem) 作者:张力升 来源:长清图书馆 阅读用时:其实年前拿到书,本来想寒假在家看的,但是在家一点儿都 ...

  7. Rabbitmq——实现消费端限流 --NACK重回队列

    如果是高并发下,rabbitmq服务器上收到成千上万条消息,那么当打开消费端时,这些消息必定喷涌而来,导致消费端消费不过来甚至挂掉都有可能. 在非自动确认的模式下,可以采用限流模式,rabbitmq ...

  8. 两年,VMware又重回巅峰?

    两年前,被公有云和容器打的焦头烂额的VMware一度被众多业界人士看衰,营收.股价双双下滑.然而,仅仅经过短短两年时间,VMware已经和AWS,IBM.微软.Rackspace等众多公有云厂商成为合 ...

  9. 纳德拉再造微软:市值如何重回第一阵营(思维确实变了,不再是以windows为中心,拥抱其它各种平台,敢在主战场之外找到适合自己的新战场)

    有人说,现在的美国硅谷充满了“咖喱味”.也有人说,硅谷已经变成“印度谷”.原因就在于,以微软CEO萨提亚·纳德拉.谷歌CEO桑达尔·皮查伊为代表的印度人,近年以来掌控了全世界最令人望而生畏的科技巨头. ...

随机推荐

  1. CSS 教程 - 闭合浮动元素

    按照CSS规范,浮动元素(floats)会被移出文档流,不会影响到块状盒子的布局而只会影响内联盒子(通常是文本)的排列. 因此当其高度超出包含容器时,一般父容器不会自动伸长以闭合浮动元素. 但是有时我 ...

  2. vue 使用 element ui动态添加表单

    html部分 <div class="hello"> <el-form :model="dynamicValidateForm" ref=&q ...

  3. 2018.8.6 模拟赛 提高组B

    T1 Description 给定一个n个点m条边的有向图,有k个标记点,要求从规定的起点按任意顺序经过所有标记点到达规定的终点,问最短的距离是多少. Input 第一行5个整数n.m.k.s.t,表 ...

  4. .Net Core 授权系统组件解析

    前面关于.Net Core如何进行用户认证的核心流程介绍完毕之后,.Net Core 认证系统之Cookie认证源码解析远程认证暂时不介绍,后期有时间,我会加上.接下去介绍认证组件是如何和认证组件一起 ...

  5. golang时间与日期相关函数

  6. java 3类的继承

    模板类 泛型程序设计方法 类的组合 类的继承 java只有单继承 隐藏和覆盖 用super.x调用 访问静态属性 静态属性不继承 静态成员只有一个,不会有副本 静态成员只有一个所有的超类和子类 方法的 ...

  7. 详解TCP三握四挥

    TCP握手协议 在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接.第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确 ...

  8. 从php到浏览器的缓存机制

    所有的php程序员都知道在php脚本里面执行 echo “1”;访客的浏览器里面就会显示“1”. 但是我们执行下面的代码的时候,并不是显示“1”之后5秒再显示“2”,而是等待5秒后直接显示“12” 这 ...

  9. bzoj3899 弦论

    好久没有更blog了啊... 对于一个给定长度为N的字符串,求它的第K小子串是什么. 这是一个SAM的模板题. 我好弱啊这个时候才开始学SAM,才会用指针. 要维护3个东西:每个状态right集合的大 ...

  10. NOIP2016提高A组模拟9.28总结

    这次三道题都是可以AC的. 每道题思路都正确,但每道题都有细节没有注意. 第一题 1.没注意系数为1时可以省略系数: 2.没注意在第一项处理常数后,不能输出+号. 导致丢失20分:一定要多出特殊数据, ...