我等蒟蒻爆零之后,问LincHpin大爷:“此等神题可有甚么来头?”

LincHpin:“此三题皆为当年ZXR前辈所留。”

固名之,ZXR专场,233~~~

T1 勤奋的YouSiki

这个题在BZOJ和HDU上都有身影,一样不一样的吧,反正意思差不多,想法也很相近。

首先就是发现mex函数的一个性质——当左端点固定时,函数值随右端点单调,即$mex(i,j) \leq mex(i,j+1)$。

然后,我们这么做:先$O(N)$求出以1位左端点,右端点分别为$i=1..n$的mex函数值,然后不断将左端点向右移动。

当左端点从$i$移动到$i+1$时,会使得$num_{i}$从维护序列中消失,考虑对那些mex函数值的影响。

首先,$mex_{1}$到$mex_{i}$的函数值已经没用了,可以忽略。

如果我们已经知道$num_{i}$下一次出现的位置是$next_{i}$,那么从$i$到$next_{i}-1$区间内的所有mex值都应当对$num_{i}$取min。

又因为mex函数值一直保持单调性,所有可以二分出来需要修改的区间,然后就变成了区间修改,区间求和,那就是线段树了。

 #include <cstdio>
#include <cstring> inline char nextChar(void)
{
static const int siz = << ; static char buf[siz];
static char *hd = buf + siz;
static char *tl = buf + siz; if (hd == tl)
fread(hd = buf, , siz, stdin); return *hd++;
} inline int nextInt(void)
{
register int ret = ;
register bool neg = false;
register char bit = nextChar(); for (; bit < ; bit = nextChar())
if (bit == '-')neg ^= true; for (; bit > ; bit = nextChar())
ret = ret * + bit - ''; return neg ? -ret : ret;
} typedef long long lnt; const int siz = ; int n, num[siz]; int nxt[siz];
int lst[siz];
int mex[siz]; bool vis[siz]; inline void prework(void)
{
for (int i = ; i <= n; ++i)
lst[i] = n + ; for (int i = n; i >= ; --i)
{
nxt[i] = lst[num[i]];
lst[num[i]] = i;
} memset(vis, false, sizeof(vis)); int ans = ; for (int i = ; i <= n; ++i)
{
vis[num[i]] = true; while (vis[ans])
++ans; mex[i] = ans;
}
} lnt sum[siz << ];
lnt tag[siz << ];
int son[siz << ]; void build(int t, int l, int r)
{
tag[t] = -; if (l == r)
sum[t] = son[t] = mex[l];
else
{
int mid = (l + r) >> ; build(t << , l, mid);
build(t << | , mid + , r); son[t] = son[t << | ];
sum[t] = sum[t << ] + sum[t << | ];
}
} inline void addtag(int t, lnt v, lnt k)
{
son[t] = v;
tag[t] = v;
sum[t] = v * k;
} inline void pushdown(int t, int l, int r)
{
int mid = (l + r) >> ;
addtag(t << , tag[t], mid - l + );
addtag(t << | , tag[t], r - mid);
tag[t] = -;
} lnt query(int t, int l, int r, int x, int y)
{
if (l == x && r == y)
return sum[t];
else
{
if (~tag[t])
pushdown(t, l, r); int mid = (l + r) >> ; if (y <= mid)
return query(t << , l, mid, x, y);
else if (x > mid)
return query(t << | , mid + , r, x, y);
else return
query(t << , l, mid, x, mid)
+ query(t << | , mid + , r, mid + , y);
}
} int query(int t, int l, int r, int v)
{
if (son[t] <= v)
return n + ; if (l == r)
return l; if (~tag[t])
pushdown(t, l, r); int mid = (l + r) >> ; int s = son[t << ]; if (s > v)
return query(t << , l, mid, v);
else
return query(t << | , mid + , r, v);
} void change(int t, int l, int r, int x, int y, lnt v)
{
if (l == x && r == y)
addtag(t, v, r - l + );
else
{
if (~tag[t])
pushdown(t, l, r); int mid = (l + r) >> ; if (y <= mid)
change(t << , l, mid, x, y, v);
else if (x > mid)
change(t << | , mid + , r, x, y, v);
else
{
change(t << , l, mid, x, mid, v);
change(t << | , mid + , r, mid + , y, v);
} son[t] = son[t << | ];
sum[t] = sum[t << ] + sum[t << | ];
}
} inline void solve(void)
{
lnt ans = 0LL; prework(); build(, , n); for (int i = ; i <= n; ++i)
{
ans += query(, , n, i, n); int pos = query(, , n, num[i]); // first > num[i] if (pos <= nxt[i] - )
change(, , n, pos, nxt[i] - , num[i]);
} printf("%lld\n", ans);
} signed main(void)
{
freopen("mex.in", "r", stdin);
freopen("mex.out", "w", stdout); n = nextInt(); for (int i = ; i <= n; ++i)
num[i] = nextInt(); for (int i = ; i <= n; ++i)
if (num[i] > n)
num[i] = n; solve(); fclose(stdin);
fclose(stdout); return ;
}

网上还有一个比较神的算法,复杂度据说是有保证的,小伙伴说是$O(NlogN)$的,我等蒟蒻目瞪口呆。

令$sum_{i}=\sum_{1 \leq j \leq i}{mex_{j,i}}$,发现这东西也具有单调性,及$sum_{i} \leq sum_{i+1}$。

然后另i从1不断变大,即sum的右端点不断右移。每次考虑新加入$num_{i}$对当前$sum$的影响。只需要计算出有多少个sum值需要+1即可,还需要暴力枚举数字,不知道为什么复杂度是有保证的,跑得还迷之快~~~

 #include <cstdio>

 const int siz = ;

 int n, num[siz], lst[siz], pos[siz];

 signed main(void)
{
freopen("mex.in", "r", stdin);
freopen("mex.out", "w", stdout); scanf("%d", &n); for (int i = ; i <= n; ++i)
scanf("%d", num + i); long long ans = 0LL, now = 0LL; for (int i = , p; i <= n; ++i, ans += now)
if (num[i] < n)
{
p = lst[num[i]];
lst[num[i]] = i; for (int j = num[i]; j < n; ++j)
{
pos[j] = lst[j];
if (j && pos[j] > pos[j - ] )
pos[j] = pos[j - ];
if (pos[j] > p)
now += pos[j] - p;
else break;
}
} printf("%lld\n", ans); return fclose(stdin), fclose(stdout), ;
}

T2 贪玩的YouSiki

贪心思想。首先左边一列点是行,右边一列点是列,中间连线表示点。然后不断找交错路,在上面交错染色。注意染色的顺序即可。别问为啥,证明请找大爷。

 #include <cstdio>
#include <algorithm> const int siz = ; int n, X[siz], Y[siz]; int mapX[siz], totX;
int mapY[siz], totY; int hd[siz], to[siz], nt[siz], tot = , ans[siz]; inline void add(int a, int b)
{
nt[++tot] = hd[a]; to[tot] = b; hd[a] = tot;
nt[++tot] = hd[b]; to[tot] = a; hd[b] = tot;
} void dfs(int u, int k)
{
int e = hd[u];
while (e && !to[e])
e = nt[e];
hd[u] = nt[e];
if (e)
{
to[e ^ ] = ;
ans[e >> ] = k;
dfs(to[e], !k);
}
} signed main(void)
{
freopen("game.in", "r", stdin);
freopen("game.out", "w", stdout); scanf("%d", &n); for (int i = ; i <= n; ++i)
{
scanf("%d%d", X + i, Y + i);
mapX[++totX] = X[i];
mapY[++totY] = Y[i];
} std::sort(mapX + , mapX + + totX);
std::sort(mapY + , mapY + + totY); totX = std::unique(mapX + , mapX + + totX) - mapX;
totY = std::unique(mapY + , mapY + + totY) - mapY; for (int i = ; i <= n; ++i)
{
X[i] = std::lower_bound(mapX + , mapX + totX, X[i]) - mapX;
Y[i] = std::lower_bound(mapY + , mapY + totY, Y[i]) - mapY;
} for (int i = ; i <= n; ++i)
add(X[i], Y[i] + totX - ); for (int i = ; i <= totX + totY - ; ++i)
for (int j = ; hd[i]; j = !j)dfs(i, j); for (int i = ; i <= n; ++i)
printf("%d", ans[i]); return fclose(stdin), fclose(stdout), ;
}

T3 另一个YouSiki

首先发现,这和数字大小没什么关系,只需要看是不是0就行,毕竟一个正数再怎么乘,再怎么加也还是正数。

然后把01矩阵看成邻接矩阵,$A^{K}$就是走$K$步,从$i$到$j$的路径方案数。题目又保证有至少一个自环,所以只需要关心连通性问题,即这个图是否满足从任意一个点都能到达其他所有点。这个,tarjan吧。

 #include <cstdio>
#include <cstring> inline char nextChar(void)
{
static const int siz = << ; static char buf[siz];
static char *hd = buf + siz;
static char *tl = buf + siz; if (hd == tl)
fread(hd = buf, , siz, stdin); return *hd++;
} inline int nextInt(void)
{
register int ret = ;
register bool neg = false;
register char bit = nextChar(); for (; bit < ; bit = nextChar())
if (bit == '-')neg ^= true; for (; bit > ; bit = nextChar())
ret = ret * + bit - ''; return neg ? -ret : ret;
} const int siz = ; int n, hd[siz], to[siz], nt[siz], tot; inline void add(int u, int v)
{
nt[++tot] = hd[u]; to[tot] = v; hd[u] = tot;
} int dfn[siz], low[siz], tim, flag; inline void Min(int &a, int b)
{
if (a > b)a = b;
} void tarjan(int u)
{
dfn[u] = low[u] = ++tim; for (int i = hd[u]; i; i = nt[i])
if (!dfn[to[i]])
tarjan(to[i]), Min(low[u], low[to[i]]);
else
Min(low[u], dfn[to[i]]); if (low[u] == dfn[u])
flag &= (u == );
} signed main(void)
{
freopen("another.in", "r", stdin);
freopen("another.out", "w", stdout); for (int cas = nextInt(); cas--; )
{
n = nextInt(); memset(hd, , sizeof(hd)), tot = ;
memset(dfn, , sizeof(dfn)), tim = ; for (int i = ; i <= n; ++i)
for (int j = ; j <= n; ++j)
if (nextInt())add(i, j); flag = true; tarjan(); for (int i = ; i <= n; ++i)
flag &= (dfn[i] != ); puts(flag ? "YES" : "NO");
} return fclose(stdin), fclose(stdout), ;
}

@Author: YouSiki

2017 01 16 校内小测 ZXR专场的更多相关文章

  1. java编程如何实现2017-01-16 22:28:26.0这样的时间数据,转换成2017:01:16:22:28:26这样的时间数据

    不多说,直接上干货! timereplace.java package zhouls.bigdata.DataFeatureSelection.util; /* * 这个程序,是用来做补充的 */ p ...

  2. [福大软工] Z班 团队作业——随堂小测(同学录) 作业成绩

    团队作业--随堂小测(同学录) 作业链接 http://www.cnblogs.com/easteast/p/7763645.html 作业情况 本次作业从原先预计的3小时,有些组打了鸡血连续肝了4. ...

  3. 2017.1.16【初中部 】普及组模拟赛C组总结

    2017.1.16[初中部 ]普及组模拟赛C组 这次总结我赶时间,不写这么详细了. 话说这次比赛,我虽然翻了个大车,但一天之内AK,我感到很高兴 比赛 0+15+0+100=115 改题 AK 一.c ...

  4. 【web开发 | 移动APP开发】 Web 移动开发指南(2017.01.05更新)

    版本记录 - 版本1.0 创建文章(2016.12.30) - 版本1.1 更正了hybird相关知识:增加了参考文章(2017.01.05): + Web APP更正为响应式移动站点与页面,简称响应 ...

  5. 小测几种python web server的性能

    http://blog.csdn.net/raptor/article/details/8038476 因为换了nginx就不再使用mod_wsgi来跑web.py应用了,现在用的是gevent-ws ...

  6. 2017.9.16~17,热烈庆祝共创力罗老师《敏捷MINI体验式实战培训》在某大型企业成功举办!

    2017.9.16~17日,深圳市共创力企业管理咨询有限公司为某上市企业提供了为期两天的内训服务.该次内训的主题为<敏捷MINI体验式实践培训>,为期两天.此次培训由共创力资深讲师Geor ...

  7. 福州大学软件工程1816 | W班 第8次作业[团队作业,随堂小测——校友录]

    作业链接 团队作业,随堂小测--校友录 评分细则 本次个人项目分数由两部分组成(博客分满分40分+程序得分满分60分) 博客和程序得分表 评分统计图 千帆竞发图 总结 旅法师:实现了更新,导出,查询, ...

  8. MySQL课堂小测

    目录 一.基本知识与操作方法 二.小测具体内容 (一)向数据库表中添加记录 (二)下载并导入world.sql (三)数据库查询与输出 (四)查询数据库并求某字段和 (五)查询数据库并取最大& ...

  9. Android开发的16条小经验总结

    Android开发的16条小经验总结,希望对各位搞Android开发的朋友有所帮助. 1. TextView中的getTextSize返回值是以像素(px)为单位的, 而setTextSize()是以 ...

随机推荐

  1. leetco Path Sum II

    和上一题类似,这里是要记录每条路径并返回结果. Given the below binary tree and sum = 22, 5 / \ 4 8 / / \ 11 13 4 / \ / \ 7 ...

  2. Entity Framework 5 自定义代码生成模板 转

    Entity Framework 5 发布有一定时间了,但学习资源确实不多,更何况英语差的我,看英语确实费力,不管怎么样,问题还是解决了,查看很多人写的文章(让我看的想放弃,更想找到答案),都没有到到 ...

  3. ssh常用用法小结

    ssh常用用法小结 1.连接到远程主机: 命令格式 : ssh name@remoteserver 或者 ssh remoteserver -l name 说明:以上两种方式都可以远程登录到远程主机, ...

  4. XLSTransformer生成excel一个简单的演示示例文件

    项目结构图: 在这些项目中使用jar.可以http://www.findjar.com/index.x下载 ExcelUtil类源代码: package util; import java.io.IO ...

  5. 阿里云1218动态css3代码

    See the Pen jEWpWm by kujian (@kujian) on CodePen. .room-nav { /* -webkit-animation:roomNavTranslate ...

  6. Windows上memcached的使用

    Memcached是什么?Memcached是由Danga Interactive开发的,高性能的,分布式的内存对象缓存系统,用于在动态应用中减少数据库负载,提升访问速度. Memcached能缓存什 ...

  7. MVC与Validate验证提示的样式修改

    MVC中使用Validate的验证,要修改错误提示样式一共有3处需要修改,否则就不太完美了: MVC中的Validate的验证机制只用在后台写一次,就可以完成前台和后台的完美验证,前台的验证主要是依靠 ...

  8. 理解对象模型图(Reading OMDS)

    理解对象模型图(Reading OMDS) 引言 这篇文章大部分内容是翻译的帮助资料里的东西.学习技术,英语是个好工具.一直把英语的地位看得和技术一样重,也会强迫自己看英语版的技术书籍(都是PDF版的 ...

  9. tcp连接以及网络I/O的几个问题

    这段时间在做一些web方面开发的事情,用的Nginx+fast-cgi,计划深入看一下Nginx的内部实现和架构,以方便理解和调优.后面准备写一篇有关Nginx介绍和深度解析的文章,要深入理解web服 ...

  10. Jquery文本框值改变事件兼容性

    Jquery文本框值改变事件(支持火狐.ie)   Jquery值改变事件支持火狐和ie浏览器,并且测试通过,绑定后台代码可以做成autocomplete控件. 具体代码列举如下: ? $(docum ...