确实是一道很不错的题啊。

题目链接

题意

感觉也没什么特别简洁的版本,大家直接看题面吧。

题解

我第一次看到这个类似问题的背景是疯狗,因此下面的题解不自觉的代入了...大家明白意思就好。

我们考虑对于疯狗,我们将其染为黑点,否则是白点。这样我们就可以用一张每个点有两种颜色的有向图来表示当前的状态。来想一想状态之间是如何转移的。

首先我们可以对每一个疯狗的主人分开考虑,计算他什么时候会发现自己的狗是疯狗,对所有的答案取\(\min\)即可。对于一个疯狗的主人,他自己能观察到的点的状态已经被确定了。于是他可以在自己的狗不疯的假设下,枚举所有他看不见的狗的状态,取其中最大的时间。可以发现状态向下的转移和这个人不能观察的人更加有关系,于是我们考虑将原图取反,在原图的补图上解决问题。此时\(i\)到\(j\)有边的意思是\(i\)不能观察\(j\)。当当前的时间等于最大时间\(+1\)时,他就会发现自己的狗是疯狗了。

那么首先要考虑的问题是怎么判断一个状态是否会永远发现不了疯狗。那么比较显然应该是转移出现了环的时候。那么什么样的图的转移会成环呢?我们假设图中有一个黑点,它可以到达图中的一个环,那么我们在转移的时候显然有一种转移是不断的把接近这个环的后继染黑,直到走到环上,接下来沿着环染黑,那么转移就会无休无止了。更准确的说,当存在一个黑点能够到达一个点数大于\(1\)的强连通分量时,就永远发现不了疯狗了。

于是我们可以发现所有能到达点数大于\(1\)的强连通分量的点都是不可以是疯狗的!那么我们就不用管这些点了。剩下的点组成了一张\(DAG\)!

于是我们只需要考虑一张每个点有两种颜色的\(DAG\)的答案就好了。这里给出一个结论:一个状态的枪响时间是所有黑点能到达的点的数目。

证明我们采用归纳法:假设对于一个状态,它能转移到的所有状态都符合这个结论了。那么我们依次考虑每个黑点,它可以将它的后继中的任意个染黑然后自己变白(当然要满足图中至少一个黑点),这样之后转移得到的答案是新的点集能到达的点数。那么由于它想要的是最大值,不难发现将所有后继染黑一定是最优的。此时除了它本身以外,它所能到达的点依然可以到达。也就是说,假如当前的其它黑点中有能够到达它的点,那么这个点的答案就是当前点集能到达的点数\(+1\),这里的加一是因为之前所说的需要多一天时间发现,否则就不加一,因为它本身已经无法到达了。

而我们需要的是所有点的答案的最小值,不难发现点集中一定有一个黑点是其它黑点无法到达的(比如拓扑序最大的点),因此“当前点集能到达的点数”这个下界总是可以取到。于是结论就成立了。

那么考虑怎么求第一问的答案。可以每个点分开算贡献。我们先用\(O(\frac{n^3}{w})\)的时间用\(\rm bitset\)求出对于每一个点能到达它的点的数目。那么对于一个点集,它会记录这个点的情况只有点集中有能到它的点。我们用所有方案减去不存在能到它的点的方案即可。

至于第二问,不难发现是求每个状态有多少点可以取到最小值。根据之前的分析,应该是不能被点集中除自己外的点到达的那些点。分开算到每个点中,就是仅包含自己和不能到自己的点的那些点集。

代码:

#include<cstdio>
#include<bitset>
#include<stack>
using std::bitset;
using std::stack;
const int mod=998244353;
inline int add(int a,int b)
{
return (a+=b)>=mod?a-mod:a;
}
inline int sub(int a,int b)
{
return (a-=b)<0?a+mod:a;
}
inline int mul(int a,int b)
{
return (long long)a*b%mod;
}
inline int qpow(int a,int b)
{
int res=1;
for(;b;a=mul(a,a),b>>=1)
if(b&1)
res=mul(res,a);
return res;
}
const int N=3005;
int n,ans,idx,cnt;
char s[N];
int g[N][N];
int dfn[N],low[N],com[N];
int size[N];
int g2[N][N];
stack<int> st;
bool inst[N];
bitset<N> from[N];
void dfs(int x)
{
register int i;
dfn[x]=low[x]=++idx;
st.push(x);inst[x]=1;
for(i=1;i<=n;i++)
if(g[x][i])
{
if(!dfn[i])
{
dfs(i);
if(low[i]<low[x])
low[x]=low[i];
}
else if(inst[i]&&dfn[i]<low[x])
low[x]=i;
}
if(dfn[x]==low[x])
{
com[x]=++cnt;size[cnt]=1;
while(st.top()!=x)
com[st.top()]=cnt,size[cnt]++,inst[st.top()]=0,st.pop();
inst[x]=0;st.pop();
}
return;
}
signed main()
{
register int i,j;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%s",s+1);
for(j=1;j<=n;j++)
if(i!=j&&s[j]=='0')
g[i][j]=1;
}
for(i=1;i<=n;i++)
if(!dfn[i])
dfs(i);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(g[i][j]&&com[i]!=com[j])
g2[com[i]][com[j]]=1;
for(i=1;i<=cnt;i++)
for(j=1;j<i;j++)
if(g2[i][j]&&size[j]>size[i])
size[i]=size[j];
int cc=0;
for(i=1;i<=cnt;i++)
if(size[i]==1)
cc++;
// for(i=1;i<=cnt;i++)
// if(size[i]==1)
// {
// to[i].set(i);
// for(j=1;j<i;j++)
// if(size[j]==1&&g2[i][j])
// to[i]|=to[j];
// }
for(i=cnt;i>=1;i--)
if(size[i]==1)
{
from[i].set(i);
for(j=cnt;j>i;j--)
if(size[j]==1&&g2[j][i])
from[i]|=from[j];
}
for(i=1;i<=cnt;i++)
if(size[i]==1)
ans=add(ans,mul(sub(qpow(2,from[i].count()),1),qpow(2,cc-from[i].count())));
printf("%d ",ans);
ans=0;
for(i=1;i<=cnt;i++)
if(size[i]==1)
ans=add(ans,qpow(2,cc-from[i].count()));
printf("%d\n",ans);
return 0;
}

UOJ #76 【UR #6】懒癌的更多相关文章

  1. 【UOJ#76】【UR #6】懒癌(动态规划)

    [UOJ#76][UR #6]懒癌(动态规划) 题面 UOJ 题解 神....神仙题. 先考虑如果是完全图怎么做... 因为是完全图,所以是对称的,所以我们只考虑一个有懒癌的人的心路历程. 如果只有一 ...

  2. UOJ #76 -【UR #6】懒癌(思维题)

    UOJ 题面传送门 神仙题. orz czx,czxyyds 首先没有懒癌的狗肯定不会被枪毙,证明显然. 接下来考虑怎样计算一种局面的答案,假设 \(dp_S\) 表示对于有且仅有 \(S\) 中的狗 ...

  3. UOJ 【UR #5】怎样跑得更快

    [UOJ#62]怎样跑得更快 题面 这个题让人有高斯消元的冲动,但肯定是不行的. 这个题算是莫比乌斯反演的一个非常巧妙的应用(不看题解不会做). 套路1: 因为\(b(i)\)能表达成一系列\(x(i ...

  4. UOJ #22 UR #1 外星人

    LINK:#22. UR #1 外星人 给出n个正整数数 一个初值x x要逐个对这些数字取模 问怎样排列使得最终结果最大 使结果最大的方案数又多少种? n<=1000,x<=5000. 考 ...

  5. UOJ.52.[UR #4]元旦激光炮(交互 思路)

    题目链接 \(Description\) 交互库中有三个排好序的,长度分别为\(n_a,n_b,n_c\)的数组\(a,b,c\).你需要求出所有元素中第\(k\)小的数.你可以调用至多\(100\) ...

  6. UOJ【UR #12】实验室外的攻防战

    题意: 给出一个排列$A$,问是否能够经过以下若干次变换变为排列$B$ 变换:若${A_i> A_i+1}$,可以${swap(A_i,A_i+1)}$ 考虑一个数字从A排列到B排列连出来的路径 ...

  7. 【UOJ#33】【UR#2】树上GCD 有根树点分治 + 容斥原理 + 分块

    #33. [UR #2]树上GCD 有一棵$n$个结点的有根树$T$.结点编号为$1…n$,其中根结点为$1$. 树上每条边的长度为$1$.我们用$d(x,y)$表示结点$x,y$在树上的距离,$LC ...

  8. uoj #118. 【UR #8】赴京赶考 水题

    #118. [UR #8]赴京赶考 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://uoj.ac/problem/118 Description ...

  9. uoj #31. 【UR #2】猪猪侠再战括号序列 贪心

    #31. [UR #2]猪猪侠再战括号序列 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://uoj.ac/problem/31 Descript ...

随机推荐

  1. Android在代码中设置控件的drawableLeft,drawableRight,drawableTop,drawableBottom。

    根据业务的需要,要在代码中设置控件的drawableLeft,drawableRight,drawableTop,drawableBottom属性. 我们知道在xml中设置的方法为:android:d ...

  2. [Synthetic-data-with-text-and-image]

    0 引言 本文是之前为了解决如何将文字贴到图片上而编写的代码,默认是如发票一类的,所以并未考虑透视变换等.且采用的是pygame粘贴方式,之前也尝试过opencv的seamlessClone粘贴. 值 ...

  3. PHP实现栈数据结构

    利用php面向对象思想,栈的属性有top.最大存储数.和存储容器(这里利用了php数组). 代码如下:实现了入栈.出栈.遍历栈的几个方法: <?php class Stack{ const MA ...

  4. excel保存为制表符分隔的文本文件 js无法完整读取

    excel保存为制表符分隔的文本文件 js无法完整读取 excel另存为文本有两个选项,一个是制表符分隔的文本文件,一个是unicode文本.生成的文件Unicode更大一些.但是这里需要注意的是[制 ...

  5. 小程序学习-理解小程序中响应式单位rpx

    微信小程序的官方文档用rpx来做响应式布局单位!那什么是rpx,应该如何设置呢?今天我们就来好好了解一下. [像素]:它不是自然界的物理长度,指基本原色素及其灰度的基本编码. [物理像素]:它是显示器 ...

  6. ASP.NET MVC中jQuery与angularjs混合应用传参并绑定数据

    要求是这样子的,在一个列表页中,用户点击详细铵钮,带记录的主键值至另一页.在另一外页中,获取记录数据,然后显示此记录数据在网页上. 先用动图演示: 昨天有分享为ng-click传递参数 <ang ...

  7. Newtonsoft的序列化和反序列化

    class test    {        public string a;       public int b;        public byte[] c;        public In ...

  8. WPF Blend 脑洞大开的问题:如何用Blend得到或画出一个凹槽、曲面。

    原文:WPF Blend 脑洞大开的问题:如何用Blend得到或画出一个凹槽.曲面. 目标图: 步骤一(放置一个矩形,填充蓝色): 步骤二(复制该矩形,并调整边角,填充粉红色): 第三部:让图形部分重 ...

  9. .NetCore实践篇:成功解决分布式监控ZipKin聚合依赖问题(三)

    前言 读本篇文章之前,可以先读前两篇文章.为了照顾没看过的朋友,我也会稍作复习. 思考大纲: .Net架构篇:思考如何设计一款实用的分布式监控系统? 实践篇一:.NetCore实践篇:分布式监控客户端 ...

  10. VS2017一步一步断点调试解决Dapper语句出现的Bug

    最近再做一个项目,出现一个小bug,bug虽小,但是却要命啊.下面我show下我解决问题的方法. View层代码: @model List<mhq.Blog.Model.Blog> < ...