T1 Article

给 $m$ 个好串,定义一个字符串分割方案是好的当且仅当它分割出来的子串中"是好串的子串"的串长占原串串长超过 85%,定义一个好的分割方案的权值为这种分割方案中每个"是好串的子串"的子串的最短长度,给 $n$ 个询问串,对每个询问串求最大权值

$n,m \leq 10^5, \sum |S|,\sum |T| \leq 10^6$

sol:

二分最短长度 $L$,做一个 dp

$f_i$ 表示前 $i$ 位字符串最多的"是好串的子串"的长度和是多少,转移就是 $f_i = max\{f_j + (i - j)\} (S[j+1,i] 是好串的子串,i-j \geq L)$

由于 $S[j+1,i]$ 的右端单调递增,可以用后缀自动机来预处理每一个 $S[1,i]$ 最大匹配长度,最大匹配长度显然是单调的,所以可以用单调队列维护 $i+f_i$

然后还要注意一点是这题 85% 以上就行,所以还要加一个 $f_i = f_{i-1}$ 的转移,最后判一下 $f_{len}$ 是否超过原串的 85%

  1. #include <bits/stdc++.h>
  2. #define LL long long
  3. #define rep(i, s, t) for(register int i = (s), i##end = (t); i <= i##end; ++i)
  4. #define dwn(i, s, t) for(register int i = (s), i##end = (t); i >= i##end; --i)
  5. using namespace std;
  6. inline int read() {
  7. int x = , f = ; char ch = getchar();
  8. for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -f;
  9. for(; isdigit(ch); ch = getchar()) x = * x + ch - '';
  10. return x * f;
  11. }
  12. const int maxn = ;
  13. int m, n;
  14. char s[maxn];
  15. int f[maxn];
  16. int root, last, dfn;
  17. int tr[maxn][], fa[maxn], mxlen[maxn], Q[maxn];
  18. inline void extend(int c) {
  19. int p = last, np = last = ++dfn;
  20. mxlen[np] = mxlen[p] + ;
  21. for(; p && !tr[p][c]; p = fa[p]) tr[p][c] = np;
  22. if(!p) fa[np] = root;
  23. else {
  24. int q = tr[p][c];
  25. if(mxlen[q] == mxlen[p] + ) fa[np] = q;
  26. else {
  27. int nq = ++dfn;
  28. mxlen[nq] = mxlen[p] + ;
  29. fa[nq] = fa[q]; fa[q] = fa[np] = nq;
  30. memcpy(tr[nq], tr[q], sizeof(tr[q]));
  31. for(; p && tr[p][c] == q; p = fa[p]) tr[p][c] = nq;
  32. }
  33. }
  34. }
  35. int chk(int mid) {
  36. int len = strlen(s + );
  37. int p = root, cl = , HD = , TL = ;
  38. rep(i, , len) {
  39. int c = s[i] - 'a';
  40. if(tr[p][c]) p = tr[p][c], cl++;
  41. else {
  42. for(; p && !tr[p][c]; p = fa[p]);
  43. if(!p) cl = , p = root;
  44. else cl = mxlen[p] + , p = tr[p][c];
  45. }
  46. f[i] = f[i - ];
  47. int lf = i - cl, rig = i - mid;
  48. if(rig < ) continue;
  49. while(HD <= TL && f[Q[TL]] - Q[TL] < f[rig] - rig) --TL;
  50. Q[++TL] = rig;
  51. while(HD <= TL && Q[HD] < lf) ++HD;
  52. if(HD <= TL)f[i] = max(f[i], i + f[Q[HD]] - Q[HD]);
  53. }
  54. return (f[len] * ) >= (len * );
  55. }
  56. int main() {
  57. // freopen("article.in","r",stdin);
  58. // freopen("article.out","w",stdout);
  59. root = last = ++dfn;
  60. n = read(), m = read();
  61. rep(i, , m) {
  62. scanf("%s", s + ); int len = strlen(s + );
  63. last = ; rep(i, , len) extend(s[i] - 'a');
  64. }
  65. rep(i, , n) {
  66. scanf("%s", s + ); int l = , r = strlen(s + ), ans = -;
  67. while(l <= r) {
  68. int mid = (l + r) >> ;
  69. if(chk(mid)) l = mid + , ans = mid;
  70. else r = mid - ;
  71. } cout << ans << '\n';
  72. }
  73. }
  74. /*
  75. 1 2
  76. babba
  77. aaaaabbba
  78. babbaabbaa
  79. */

T2 work

Nick最近在玩一款很好玩的游戏,游戏规则是这样的:
有一个n*m的地图,地图上的每一个位置要么是空地,要么是炮塔,要么是一些BETA狗,Nick需
要操纵炮塔攻击BETA狗们。
攻击方法是:对于每个炮塔,游戏系统已经给出它可以瞄准的方向(上下左右其中一个),Nick需要
选择它的攻击位置,每一个炮塔只能够攻击一个位置,炮塔只能够向着它的瞄准方向上的某个位置发
动攻击,当然炮塔也可以不进行攻击。炮塔威力强大,它可以且仅可以消灭目标位置上所有的BETA狗。
出于安全考虑,游戏系统已经保证不存在一个炮塔能够瞄准另外一个炮塔,即对于任意一个炮
塔,它所有可能的攻击位置上不存在另外一个炮塔。而且,如果把炮塔的起点和终点称为炮弹的运行
轨迹,那么系统不允许两条轨迹相交f包括起点和终点)。
现在,选定目标位置以后,每一个炮塔同时开炮,你要告诉Nick,他最多可以干掉多少BETA狗。
 
$n,m \leq 50$

考场上 sb 了,一直觉得这题是个费用流,然后死磕,然后磕死

然后发现这是一个小清新最小割题...

考虑两个从 $A$,$B$ 出发“相交”的炮弹是什么样的,显然可以看成最多拐一个弯的连接 $A,B$ 的路径,任意一个合法方案必然不包含这样的路径,所以相当于割掉这条路径的一边,于是是最小割...

一开始搜出所有路径最大值,然后减去最小代价就是答案

“最多拐一个弯”可以这样:把一个点拆成纵和横,然后纵横分别连边,每个点纵向横连 inf 即可

  1. #include <bits/stdc++.h>
  2. #define LL long long
  3. #define rep(i, s, t) for(register int i = (s), i##end = (t); i <= i##end; ++i)
  4. #define dwn(i, s, t) for(register int i = (s), i##end = (t); i >= i##end; --i)
  5. using namespace std;
  6. inline int read() {
  7. int x = , f = ; char ch = getchar();
  8. for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -f;
  9. for(; isdigit(ch); ch = getchar()) x = * x + ch - '';
  10. return x * f;
  11. }
  12. const int oo = , maxn = ;
  13. struct Dinic {
  14. int n, m, s, t;
  15. int cur[maxn], head[maxn], nx[maxn];
  16. struct Edge {
  17. int from, to, caps;
  18. Edge() {}
  19. Edge(int _1, int _2, int _3) : from(_1), to(_2), caps(_3) {}
  20. } es[maxn];
  21. void add(int u, int v, int w) {
  22. es[m] = Edge(u, v, w);
  23. nx[m] = head[u];
  24. head[u] = m++;
  25. es[m] = Edge(v, u, );
  26. nx[m] = head[v];
  27. head[v] = m++;
  28. }
  29. Dinic() {
  30. m = ;
  31. memset(head, -, sizeof(head));
  32. }
  33. queue<int> q;
  34. int dis[maxn];
  35. int BFS() {
  36. for (int i = ; i <= n; i++) dis[i] = ;
  37. dis[t] = ;
  38. q.push(t);
  39. while (!q.empty()) {
  40. int now = q.front();
  41. q.pop();
  42. for (int i = head[now]; i != -; i = nx[i]) {
  43. Edge &e = es[i ^ ];
  44. if (!dis[e.from] && e.caps) {
  45. dis[e.from] = dis[now] + ;
  46. q.push(e.from);
  47. }
  48. }
  49. }
  50. return (dis[s] > );
  51. }
  52. int DFS(int u, int a) {
  53. if (u == t || !a)
  54. return a;
  55. int flow = , f;
  56. for (int &i = cur[u]; i != -; i = nx[i]) {
  57. Edge &e = es[i];
  58. if (dis[e.to] == dis[u] - && (f = DFS(e.to, min(e.caps, a)))) {
  59. flow += f;
  60. a -= f;
  61. e.caps -= f;
  62. es[i ^ ].caps += f;
  63. if (a == )
  64. return flow;
  65. }
  66. }
  67. return flow;
  68. }
  69. int MaxFlow(int _s, int _t) {
  70. s = _s, t = _t;
  71. int flow = , f;
  72. while (BFS()) {
  73. for (int i = ; i <= n; i++) cur[i] = head[i];
  74. while (f = DFS(s, oo)) flow += f;
  75. }
  76. return flow;
  77. }
  78. } sol;
  79. int pos[][][], dfn;
  80. const int dx[] = {, -, , , };
  81. const int dy[] = {, , , -, };
  82. inline int t(int i, int j, int type) { return pos[i][j][type] ? pos[i][j][type] : (pos[i][j][type] = ++dfn); }
  83. int n, m, S, T, ans;
  84. int a[][];
  85. int main() {
  86. n = read(), m = read();
  87. rep(i, , n) rep(j, , m) {
  88. a[i][j] = read();
  89. sol.add(t(i, j, ), t(i, j, ), oo);
  90. } S = ++dfn, T = ++dfn;
  91. rep(i, , n) rep(j, , m) {
  92. if(a[i][j] >= ) continue;
  93. int opt = -a[i][j]; a[i][j] = ;
  94. int cx = i + dx[opt], cy = j + dy[opt], mx = ;
  95. while(cx >= && cx <= n && cy >= && cy <= m) {
  96. mx = max(mx, a[cx][cy]);
  97. cx += dx[opt], cy += dy[opt];
  98. }
  99. ans += mx;
  100. if(opt <= ) {
  101. int cx = i + dx[opt], cy = j + dy[opt];
  102. sol.add(S, t(i, j, ), oo);
  103. while(cx >= && cx <= n && cy >= && cy <= m) {
  104. sol.add(t(cx - dx[opt], cy - dy[opt], ), t(cx, cy, ), mx - a[cx - dx[opt]][cy - dy[opt]]);
  105. cx += dx[opt], cy += dy[opt];
  106. }
  107. }
  108. else {
  109. int cx = i + dx[opt], cy = j + dy[opt];
  110. sol.add(t(i, j, ), T, oo);
  111. while(cx >= && cx <= n && cy >= && cy <= m) {
  112. sol.add(t(cx, cy, ), t(cx - dx[opt], cy - dy[opt], ), mx - a[cx - dx[opt]][cy - dy[opt]]);
  113. cx += dx[opt], cy += dy[opt];
  114. }
  115. }
  116. } sol.n = dfn;
  117. cout << ans - sol.MaxFlow(S, T) << endl;
  118. }

T3 sej

一个长度为 $n$ 的排列 $\{a_i\}$,定义 $p_x = max_{i=1}^x a_i$,$s_x = max_{i=x}^n a_i$

对这个排列求出 $p$ 数组和 $s$ 数组,将 $p,s$ 分别去重、排序,求 $p,s$ 长度分别为 $a,b$ 的排列有多少个

$n,a,b \leq 100000$

sol:

发现 $p$ 数组和 $s$ 数组一定能变成一个峰,两边递减,而两边的情况是对称的,于是可以考虑枚举每次左边,右边峰的出现

记 $f_{(i,j)}$ 表示插入了前 $i$ 大的数,左边的峰改变了$j$ 次的排列数

考虑每次把 $1$ 加进去,就是 $f_{(i,j)} = f_{(i-1,j-1)} + (i-1) \times f_{(i-1,j)}$

因为左右时对称的,所以这也是右边的峰改变了 $j$ 次的排列数,由于最后一个 $n$ 和第一个 $1$ 会同时改变左右的峰,所以一共改变次数是 $a+b-2$

这 $a+b-2$ 中,有 $a-1$ 次是单独改左边(把 $1$ 和 $n$ 分配给左右边),考虑改的是哪几次,显然有 $\binom{a+b-2}{a-1}$ 种方法,于是答案就是 $f_{(n,a+b-2)} \times \binom{a+b-2}{a-1}$

然后发现 $f$ 就是第一类斯特林数,考虑第一类斯特林数的下降幂形式 $\prod\limits_{i=1}^{n-1} (x-i) = \sum\limits_{i=0}^n (-1)^{(n-i)} \times Stirling1(n,i) \times x^i$

右边是个生成函数,左边是 $n$ 个多项式相乘

所以分治+FFT即可

  1. #include <bits/stdc++.h>
  2. #define LL long long
  3. #define rep(i, s, t) for(register int i = (s), i##end = (t); i <= i##end; ++i)
  4. #define dwn(i, s, t) for(register int i = (s), i##end = (t); i >= i##end; --i)
  5. using namespace std;
  6. inline int read() {
  7. int x = , f = ; char ch = getchar();
  8. for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -f;
  9. for(; isdigit(ch); ch = getchar()) x = * x + ch - '';
  10. return x * f;
  11. }
  12. const int mod = , maxn = ;
  13. inline int inc(int x, int y) { x += y; if(x >= mod) x -= mod; return x; }
  14. inline int dec(int x, int y) { x -= y; if(x < ) x += mod; return x; }
  15. inline int mul(int x, int y) { return 1LL * x * y % mod; }
  16. inline int ksm(int x, int t, int res = ) {
  17. for(; t; x = mul(x, x), t = t >> )
  18. if(t & ) res = mul(res, x); return res;
  19. }
  20. int f[maxn], fac[maxn], ifac[maxn], lg[maxn], r[maxn];
  21. inline int C(int x, int y) { return mul(fac[x], mul(ifac[y], ifac[x - y])); }
  22. vector<int> G[maxn];
  23. int A[maxn], B[maxn], fnl[maxn];
  24. inline void fft(int *a, int n, int f) {
  25. rep(i, , n-) r[i] = (r[i >> ] >> ) | ((i & ) << (lg[n] - ));
  26. rep(i, , n-) if(i < r[i]) swap(a[i], a[r[i]]);
  27. for(register int i = ; i < n; i <<= ) {
  28. int wn = ksm(, (mod - ) / (i << ));
  29. if(f == -) wn = ksm(wn, mod - );
  30. for(register int j = ; j < n; j += (i << )) {
  31. int w = ;
  32. for(register int k = ; k < i; ++k, w = mul(w, wn)) {
  33. int x = a[j + k], y = mul(w, a[j + k + i]);
  34. a[j + k] = inc(x, y);
  35. a[j + k + i] = dec(x, y);
  36. }
  37. }
  38. }
  39. if(f == -) {
  40. int inv_n = ksm(n, mod - );
  41. rep(i, , n-) a[i] = mul(a[i], inv_n);
  42. }
  43. }
  44. inline int mul(int wlen) {
  45. fft(A, wlen, ); fft(B, wlen, );
  46. rep(i, , wlen - ) A[i] = mul(A[i], B[i]);
  47. fft(A, wlen, -); --wlen;
  48. while(!A[wlen])--wlen; return wlen;
  49. }
  50. inline int Mul(int l, int r) {
  51. if(l == r) return G[l].size() - ;
  52. int mid = (l + r) >> ;
  53. int ls = Mul(l, mid), rs = Mul(mid + , r);
  54. int len = ; for(; len <= (ls + rs); len <<= );
  55. rep(i, , ls) A[i] = G[l][i]; rep(i, ls+, len) A[i] = ;
  56. rep(i, , rs) B[i] = G[mid+][i]; rep(i, rs+, len) B[i] = ;
  57. G[l].clear(); G[mid+].clear(); len = mul(len);
  58. rep(i, , len) G[l].push_back(A[i]);
  59. return len;
  60. }
  61. int n, a, b;
  62. int main() {
  63. // freopen("sej.in","r",stdin);
  64. // freopen("sej.out","w",stdout);
  65. lg[] = -; rep(i, , maxn - ) lg[i] = lg[i >> ] + ;
  66. n = read(), a = read(), b = read();
  67. fac[] = fac[] = ifac[] = ifac[] = ;
  68. rep(i, , a + b) fac[i] = mul(fac[i - ], i);
  69. rep(i, , a + b) ifac[i] = mul(dec(, mod / i), ifac[mod % i]);
  70. rep(i, , a + b) ifac[i] = mul(ifac[i], ifac[i - ]);
  71. n--; rep(i, , n) G[i].push_back(dec(, i-)), G[i].push_back();
  72. Mul(, n); rep(i, , G[].size() - ) fnl[i] = G[][i];
  73. rep(i, , n) if((n-i) & ) fnl[i] = mul(fnl[i], dec(, ));
  74. cout << mul(fnl[a + b - ], C(a + b - , a - )) << endl;
  75. }

NOI 模拟赛的更多相关文章

  1. NOI模拟赛 Day1

    [考完试不想说话系列] 他们都会做呢QAQ 我毛线也不会呢QAQ 悲伤ING 考试问题: 1.感觉不是很清醒,有点困╯﹏╰ 2.为啥总不按照计划来!!! 3.脑洞在哪里 4.把模拟赛当作真正的比赛,紧 ...

  2. 6.28 NOI模拟赛 好题 状压dp 随机化

    算是一道比较新颖的题目 尽管好像是两年前的省选模拟赛题目.. 对于20%的分数 可以进行爆搜,对于另外20%的数据 因为k很小所以考虑上状压dp. 观察最后答案是一个连通块 从而可以发现这个连通块必然 ...

  3. NOI 模拟赛 #2

    得分非常惨惨,半个小时写的纯暴力 70 分竟然拿了 rank 1... 如果 OYJason 和 wxjor 在可能会被爆踩吧 嘤 T1 欧拉子图 给一个无向图,如果一个边集的导出子图是一个欧拉回路, ...

  4. 【2018.12.10】NOI模拟赛3

    题目 WZJ题解 大概就是全场就我写不过 $FFT$ 系列吧……自闭 T1 奶一口,下次再写不出这种 $NTT$ 裸题题目我就艹了自己 -_-||| 而且这跟我口胡的自创模拟题 $set1$ 的 $T ...

  5. NOI模拟赛Day5

    T1 有and,xor,or三种操作,每个人手中一个数,求和左边进行某一种运算的最大值,当t==2时,还需要求最大值的个数. test1 20% n<=1000 O(n^2)暴力 test2 2 ...

  6. NOI模拟赛Day4

    看到成绩的时候我的内心** woc第一题写错了呵呵呵呵呵呵呵呵 人不能太浪,会遭报应的** ------------------------------------------------------ ...

  7. NOI模拟赛Day3

    终于A题啦鼓掌~开心~ 开考看完题后,觉得第二题很好捏(傻叉上线 搞到十一点准备弃疗了然后突然发现我会做第一题 于是瞎码了码,就去准备饭票了... 好了,停止扯淡(就我一个我妹子每天不说话好难受QAQ ...

  8. NOI模拟赛Day2

    深深的感受到了自己的水 ---------------------------------------------------------------------------------------- ...

  9. 【NOI模拟赛(湖南)】DeepDarkFantasy

    DeepDarkFantasy 从东京出发,不久便到一处驿站,写道:日暮里.  ——鲁迅<藤野先生> 定义一个置换的平方为对1~n的序列做两次该置换得到的序列.已知一个置换的平方,并且这个 ...

随机推荐

  1. ZJOI2017游记

    $Day$ $-1$ 听说可以去$ZJOI2017$打酱油,终于可以出去走走辣$QAQ$... 上次出去打比赛似乎是$PKUSC$?? 好吧,至少可以一览国家预备队爷们的风采... 准备把膝盖留在浙江 ...

  2. 【Bitset】重识

    ---------------------------------------------------------------------------- 一题题目: 一题题解: 这个题目哪来入门再好不 ...

  3. chengdongyue的笔记

    ---------------------------------------- Linux 基础 --------------------------------1.Linux的诞生 1.unix两 ...

  4. Floyd判圈算法 Floyd Cycle Detection Algorithm

    2018-01-13 20:55:56 Floyd判圈算法(Floyd Cycle Detection Algorithm),又称龟兔赛跑算法(Tortoise and Hare Algorithm) ...

  5. IntelliJ IDEA 左侧显示/展开类中的方法

    困扰我很久的问题: project直接右键: 打开.关闭对应效果: 之前查到的都是 : 虽然也有类似的功能,但是展开的是右侧窗口中,打开的那个类的: 即使不是我想要的,但也是不错的功能!

  6. 如何在 Ubuntu 中安装 QGit 客户端

    QGit是一款由Marco Costalba用Qt和C++写的开源的图形界面 Git 客户端.它是一款可以在图形界面环境下更好地提供浏览版本历史.查看提交记录和文件补丁的客户端.它利用git命令行来执 ...

  7. centos网卡配置

    DEVICE=物理设备名 IPADDR=IP地址 NETMASK=掩码值 NETWORK=网络地址 BROADCAST=广播地址 GATEWAY=网关地址 TYPE=Ethernet (网络类型)ON ...

  8. POJ 2891 中国剩余定理的非互质形式

    中国剩余定理的非互质形式 任意n个表达式一对对处理,故只需处理两个表达式. x = a(mod m) x = b(mod n) km+a = b (mod n) km = (a-b)(mod n) 利 ...

  9. JavaScript--跨域

    跨域 什么是跨域? 跨域请求就是不同域的网站之间的文件数据之间的传送 ,由于浏览器的同源策略机制(基于安全,同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性)Ajax直接请求普通 ...

  10. printf %m

    最近看别人的项目发现有 printf("%m") 这种写法,这是什么输出格式呢? 通过 man 查找得知: m (Glibc extension.) Print output of ...