我等蒟蒻爆零之后,问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. 警惕使用WebClient.DownloadFile(string uri,string filePath)方法

    原文:警惕使用WebClient.DownloadFile(string uri,string filePath)方法 WebClient.DownloadFile(string uri,string ...

  2. 浏览器检测(BrowserDetect.js)使用

    浏览器检测是在工作中经常用到的,如果只是简单判断当前是什么浏览器的话可以通过window.navigator.useragent这样的js来直接判断就可以了! 但是针对浏览器版本要求比较高的时候,如果 ...

  3. dbcp的配置

    tomcat的 配置,进入conf->context.xml <Resource name="mysql"     auth="Container" ...

  4. SpringMVC全注解

    SpringMVC全注解不是你们那么玩的 前言:忙了段时间,忙得要死要活,累了一段时间,累得死去活来. 偶尔看到很多零注解配置SpringMVC,其实没有根本的零注解. 1)工程图一张: web.xm ...

  5. Oracle 补丁及opatch 工具介绍

    一. CPU(Critical Patch Update) 一个CPU内包含了对多个安全漏洞的修复,并且也包括相应必需的非安全漏洞的补丁.CPU是累积型的,只要安装最新发布的CPU即可,其中包括之前发 ...

  6. 基于多重信号分类算法的DOA估计

    原创博文,转载请注明出处 下面的论文是我的雷达处理的作业,拿来共享,不喜勿喷.由于公式编辑器的原因,无法复制公式,全部内容请点击. 基于多重信号分类算法的DOA估计 1引言 多重信号分类(MUSIC) ...

  7. UVA 10392 (13.07.28)

    Problem F: Factoring Large Numbers One of the central ideas behind much cryptography is that factori ...

  8. warfare(最大生成树裸题)

                                                                                                  战争 [问题 ...

  9. C# 让程序自动以管理员身份运行

    exe在Vista或Win7下不以管理员权限运行,会被UAC(用户帐户控制)阻止访问系统某些功能,如修改注册表操作等;如何让exe以管理员权限运行呢,方法有两种,一个是直接修改exe属性;另一个是在程 ...

  10. 使用VS2010命令提示窗口操作程序集强命名

    说明:文中示例均以将文件置于D盘根目录(D:\)下为例. 一.查看程序集是否具有强命名 sn -T d:\LicBase.dll 若有则会显示PublicKeyToken值,反之不会. 二.给无强命名 ...