P5676 [GZOI2017]小z玩游戏【Tarjan】
小z玩游戏
Tarjan算是板子题吧,但是要稍微做一些修改,建边需要多考虑,建立“虚点”。
题目描述
小 z 很无聊。
小 z 要玩游戏。
小 z 有\(N\)个新游戏,第\(i\)个游戏看上去的有趣程度为\(w_i\)。小 z 很挑,他只会玩看上去的有趣程度是自己兴奋程度整数倍的游戏。由于游戏实际上有好玩的也有不好玩的,玩完第\(i\)个游戏后,小 z 的兴奋程度会变为\(e_i\) 。
已知小 z 初始兴奋程度为\(1\),请问小 z 有多少个游戏可能会玩两次?
输入格式
第一行一个正整数\(T\),表示测试数据组数,最多\(10\)组。
对于每组测试数据:
第一行一个正整数\(N\),表示游戏的个数。第二行\(N\)个正整数,第\(i\)个数\(w_i\) ,表示第\(i\)个游戏看上去的有趣程度为\(w_i\) 。第三行\(N\)个正整数,第\(i\)个数\(e_i\),表示小 z 玩完第\(i\)个游戏后,小 z 的兴奋程度会变为\(e_i\) 。
输出格式
共\(T\)行。
每行一个正整数,表示对应测试数据,小 z 可能会玩两次的游戏数量。
输入输出样例
输入
5
1
100000
100000
5
1 2 6 15 35
5 7 9 2 3
5
2 3 5 35 21
7 11 7 3 2
10
6 15 77 12 24 37 35 99 55 42
4 2 5 7 11 3 6 8 9 10
10
6540 5604 567 57065 60 670 6870 1230 465 6540
12 5 37 3 34 13 17 18 10 12
输出
1
3
3
8
5
说明/提示
【样例第 2 组数据解释】
数字代表游戏编号,箭头表示下一个。
可能的情况 \(1:2->5->4->2\)
可能的情况 \(2:5->4->2->5\)
可能的情况 \(3:4->2->5->4\)
所以小 z 可能玩 \(2,4,5\) 两次。
小 z 无论如何都不能玩 \(1\) 或 \(3\) 两次。
【数据约束】

分析
这个题看完题目,就很容易能够想到如果一个游戏能玩两边,那么肯定是游戏与游戏之间玩的时候形成了一个环,那么久可以想到用\(Tarjan\)求强连通分量,然后找出每个环的大小,最后加和就可以。但是如果把每一个游戏和玩完游戏的兴奋程度都建边,看一下数据范围,肯定是不能\(AC\)的,所以我们要考虑一下怎么建边。因为每玩一个游戏,兴奋程度都会有变化,而只有游戏的兴奋程度是他的兴奋程度的整数倍才会去玩,所以我们从第几个游戏到玩完这个游戏的兴奋程度建边,然后在每个游戏的有趣程度和此游戏中再建一条边,最后再从每个兴奋程度到它所能满足的有趣程度建一个边,这样就实现了原来\(n^2\)的建图方式来达到从当前游戏对下一个能玩的游戏建边的目的。下边是第二组样例中建好的图

这个图中强连通分量一共有三个点,所以答案就是三,然后按照优化的建边方法,就可以\(AC\)了(温馨提示:\(Tarjan\)一定要认真写,本人\(Tarjan\)写挂了,乱七八糟,重写一遍才改过来。)
在\(Tarjan\) 的时候,要记录强连通分量大小,大于1就标记当前点,然后运行的时候在强连通分量里的也要都标记,最后从\(1\)到\(n\)统计标记数,得出答案。
时间复杂度的证明,借用一下\(Luogu\)大佬的分析

代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e6+10;
int head[maxn],vis[maxn];
int c[maxn];
int num;
int dfn[maxn],low[maxn];
int next[maxn],ver[maxn];
int tot,cnt;
int sta[maxn];
int top;
void Add(int x,int y){//建图
ver[++tot] = y;
next[tot] = head[x];
head[x] = tot;
}
void Tarjan(int u){//求值
sta[++top]=u;
dfn[u]=low[u]=++num;
for(int i=head[u];i;i=next[i]){
int v=ver[i];
if(!dfn[v]){
Tarjan(v);
low[u]=min(low[u],low[v]);
}else if(!c[v])
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
c[u]=++cnt;
int siz=1;
while(sta[top]!=u){
c[sta[top]]=cnt;//标记当前点在第几个分量里
vis[sta[top]]=1;//标记当前点
siz++;//枚举一个点的时候就大小加一
top--;
}
if(siz>1)vis[u]=1;//不是一个点的强连通分量就标记当前点
--top;
}
}
int n;
int T;
int main(){
scanf("%d",&T);
while(T--){//初始化
memset(vis,0,sizeof(vis));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(c,0,sizeof(c));
memset(next,0,sizeof(next));
memset(ver,0,sizeof(ver));
memset(sta,0,sizeof(sta));
memset(head,0,sizeof(head));
num = 0;
tot = 0;
cnt = 0;
top = 0;
scanf("%d",&n);
int Max = 0;
for(int i=1,x;i<=n;++i){//从玩完这个游戏的兴奋度到这个游戏建边
scanf("%d",&x);
Add(n+x,i);
Max = max(Max,x);
}
for(int i=1,x;i<=n;++i){//从该游戏到该游戏的有趣度建边
scanf("%d",&x);
Add(i,n+x);
}
for(int i=1;i<=Max;++i){//从该游戏兴奋度到有趣度建边,相当于连接上能连续玩的两个点
for(int j=2;j*i<=Max;++j){
Add(n+i,n+i*j);
}
}
for(int i=1;i<=n;++i){
if(!dfn[i])Tarjan(i);
}
int ans = 0;
for(int i=1;i<=n;++i){//统计答案
if(vis[i])ans++;
}
printf("%d\n",ans);
}
}
P5676 [GZOI2017]小z玩游戏【Tarjan】的更多相关文章
- P5676 [GZOI2017]小z玩游戏 Tarjan+优化建图
题目描述 分析 一开始看到这道题,首先想到的就是建好边后跑一个Tarjan缩点,将siz大于1的节点统计一下,输出结果 Tarjan非常显然易得,关键就是怎么建边 比较好想的一种思路就是枚举每一个兴奋 ...
- 【题解】 [GZOI2017]小z玩游戏
题目戳我 \(\text{Solution:}\) 考虑建图.操作可以看作对\(1\)进行的操作,于是有以下运行过程: \(1\to w[i]\to e[i]\to...\) 考虑倍数,一个数可以走到 ...
- 神奇的建图方式(Tarjan)——小z玩游戏
原题来自与:洛谷 P5676(GZOI2017) 链接: https://www.luogu.com.cn/problem/P5676 题面: 题意比较明显,如果已经建好了边,那么跑个Tarjan ...
- 二分图【洛谷P2175】 小Z的游戏分队
P2175 小Z的游戏分队 小Z受不了寂寞,准备举办一次DOTA比赛,为了能让ACM班全部都参加比赛,他还特制了一张DOTA地图能够支持任意多人打任意多人. 现在问题来了,怎么把这么多人分成两队?小Z ...
- JZOJ 5777. 【NOIP2008模拟】小x玩游戏
5777. [NOIP2008模拟]小x玩游戏 (File IO): input:game.in output:game.out Time Limits: 1000 ms Memory Limits ...
- 2783: 【基础】小 X 玩游戏(game)
2783: [基础]小 X 玩游戏(game) 时间限制: 1 Sec 内存限制: 64 MB 提交: 752 解决: 294 [提交] [状态] [讨论版] [命题人:ghost79] 题目描述 听 ...
- SCUT - 131 - 小P玩游戏II - 贪心 - 平衡树
https://scut.online/p/131 首先假如钦定了一群人去打怪兽,那么可以把主要的任务都丢给b最大的人去打,这样不会更差.然后考虑枚举这个b最大的人,其他人陪练.一开始就是ai+k*b ...
- CONTEST36 小Z的模拟赛(2)
A.小Z的可恶路障 题目:http://www.luogu.org/problem/show?pid=U126 题解:暴力也可以过吧.我为了保险先求了一次最短路,然后枚举这条最短路上的所有边... 代 ...
- J - 玩游戏
小A和小B玩游戏,初始的时候小A给小B一组包含n个数的数组.他们按如下的规则进行: 每次小B得到一组数,他把这组数的和加到自己的分数里面(他的初始分数是0),然后他把这组数还给小A. 如果小A得到的这 ...
随机推荐
- Java实现 LeetCode 807 保持城市天际线 (暴力)
807. 保持城市天际线 在二维数组grid中,grid[i][j]代表位于某处的建筑物的高度. 我们被允许增加任何数量(不同建筑物的数量可能不同)的建筑物的高度. 高度 0 也被认为是建筑物. 最后 ...
- Java实现 蓝桥杯 算法提高 套正方形(暴力)
试题 算法提高 套正方形 问题描述 给定正方形边长width,如图按规律输出层层嵌套的正方形图形. 注意,为让选手方便观看,下图和样例输出均使用""代替空格,请选手输出的时候使用空 ...
- Java实现 LeetCode 435 无重叠区间
435. 无重叠区间 给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠. 注意: 可以认为区间的终点总是大于它的起点. 区间 [1,2] 和 [2,3] 的边界相互"接触& ...
- java中装箱和拆箱的详细使用(详解)
一.什么是装箱?什么是拆箱? 在前面的文章中提到,Java为每种基本数据类型都提供了对应的包装器类型,至于为什么会为每种基本数据类型提供包装器类型在此不进行阐述,有兴趣的朋友可以查阅相关资料.在Jav ...
- java实现报数游戏
报数游戏 有n个孩子站成一圈,从第一个孩子开始顺时针方向报数,报到3的人出列,下一个人继续从1报数,直到最后剩下一个孩子为止.问剩下第几个孩子.下面的程序以10个孩子为例,模拟了这个过程,请完善之(提 ...
- java实现第三届蓝桥杯填算式
** 填算式** [结果填空] (满分11分) 看这个算式: ☆☆☆ + ☆☆☆ = ☆☆☆ 如果每个五角星代表 1 ~ 9 的不同的数字. 这个算式有多少种可能的正确填写方法? 173 + 286 ...
- java代码(15) ---java8 Function 、Consumer 、Supplier
Java8 Function.Consumer.Supplier 有关JDK8新特性之前还有三篇博客: 1,java代码(1)---Java8 Lambda 2,java代码(2)---Java8 S ...
- Python学习之计算机基础
计算机基础: (1)计算机俗称电脑,是现代用于高速计算的电子计算器,可以进行数值计算也可以进行逻辑计算,还有存储记忆功能.是能够按照程序运行,自动,高速处理海量数据的现代化智能 电子设备. (2)物理 ...
- 用Java模拟游戏重力的实现(弹跳)
年末开了Java实训大作业 想了好几天决定选择马里奥小游戏 发现即使做出来但是跳跃功能是很“笨拙”的,和我们玩的游戏不一样,没有跳跃速度的快慢什么的,后来才知道这个叫做游戏里面重力的模拟. 组队做系统 ...
- Debian安装无线网卡Ralink RL5390驱动
惠普一体机用的无线网卡是Ralink的 RL5390,安装Debian10以后没有驱动,网上下载firmware-misc-nonfree_20190114-2_all.deb 和firmware-r ...