根本听不懂的也看不懂的上课笔记第六弹

https://qoj.ac/problem/8815

我们假设现在受到了一次攻击

那么我们就知道了后面可能攻击的集合

设当前可能被攻击的集合为S

设f(S)为对于这个集合下的期望值

记作cost1,cost2

cost1记作受攻击或付出代价

cost2实际上并不受到决策影响

对于cost2

取到每一个元素都是

1 ∣ S ∣ ∑ v ∈ S f ( S − { v } ) \frac{1}{|S|}\sum_{v\in S}f(S-\{v\}) S1vSf(S{v})

所以并不受决策影响

我们在决策中选较小值

枚举剩下的集合T, T ∈ S T\in S TS

概率为 ∑ T ∈ S 1 ( ∣ S ∣ ∣ T ∣ ) m i n { m , a v g { T } } \sum_{T\in S}\frac{1}{\binom{|S|}{|T|}}min\{m,avg\{T\}\} TS(TS)1min{m,avg{T}}

只需要知道T的大小,做一个2维背包即可


https://acm.hdu.edu.cn/showproblem.php?pid=7437

我们先考虑x是偶数的情况

每次等概率选取字符,

设alice的串为a1,a2,a3…an/2

Bob的为b1,b2,b3…bn/2

那么我们现在交换a1,b1…我们发现概率不变

所以对于每一个a,b

那么pr[a>b] = pr[a<b]

= /-pr[a>b] = pr[a=b]

那么就转化成了求解a=b的概率,简单了很多

先认为每个字符的出现都是不同的

总排列数即n!

那么取到相同数的概率就是

1 n ! ( n / 2 ) ! ∏ c c n t c \frac{1}{n!}\frac{(n/2)!}{\prod_{c}cnt^c} n!1ccntc(n/2)!

(上式可能没抄全,慎看)

奇数下的情况可以类推

设n=2k+1

那么Alice一定取了k+1个

那么靠率前k个

考虑一个字符出现的情况为奇数

那么他在结尾


https://qoj.ac/problem/8819

(很简单啊这个题

先考虑在已有字符串中新加入一个字符

找到之前有没有一个字符和这个字符相等

寻找本质不同的子串数和加入后的

考虑前n个,通过询问n和n+1

确定一个前缀,我们二分一个位置

可以了解后半段和前半段出现的位置

前面的询问是已知的,

通过可以的任何字符串方法算就可以)什么叫任何的????


https://acm.hdu.edu.cn/showproblem.php?pid=7453

我们可以对时间进行扫描线

使用数据结构维护天数

瞬时速度为

v t = ∑ i = 1 n v t − 1 + v t 2 v_t = \sum_{i=1}^{n}\frac{v_{t-1}+v_t}{2} vt=i=1n2vt1+vt

这样我们就可以维护每个顺势速度

假设对于当前的 v i − 1 , t v_{i-1},t vi1,t,我们的目标速度是 g i , t g_{i},t gi,t

在这里从i-1到i速度发生变

我们维护每次加减

对于每一天,si,ti变化,那么si,ti相对的前后缀发生变化

在线段树上维护最大最小值

维护每一段加一减一即可

复杂度分析:

对于
∑ ∣ v i , t − v i − 1 , t ∣ \sum|v_{i,t}-v_{i-1,t}| vi,tvi1,t

每次找一段,都会使整个一段变化

共q次

复杂度O((n+m)logm)


https://codeforces.com/gym/105112/problem/B

先考虑一种不全相等的方案,

考虑直接排列,方案会不会是好的

考虑交叉点会不会重合

将分割点向后移动

考虑将最后一个与第一个交换

考虑对每几个集合,

可以拼接成某个大小,

如此合并,最终成为一个好的,

或者出现中间有相交的地方

只需要求解一个方案使得合法可能数尽量多

做一个背包,假设是一个宽度不同的多重背包

使用bitset优化,再做任意的背包即可


https://codeforces.com/gym/105139/problem/C

我们对图形砍若干刀,

使得变成规则的形状

对于一个形状,我们将所有凹进的角切掉即可

我们使整个矩形失去一部分

切出巨星的个数是内角和除以360

如果一次切到两个凹角,

那么就会减少一个

我们分析边数,发现线段数绝对不会超过顶点数

使用二分图)???

建边跑匹配

复杂度O(n^2)


https://www.luogu.com.cn/problem/CF1989F

只有来那种操作可以改变颜色

将一行转化为蓝色或红色

p r i > = p c j p_{ri}>=p_{cj} pri>=pcj p r i < = p c j p_{ri}<=p_{cj} pri<=pcj

那么进行连边

如果是同一个强连通分量

考虑分治

我们让他尽量递归到前面和后面

那么边就可以分为两类:

强连通分量内和强连通分量外

我们考虑在前半部分不需要合并,

只考虑后半段即可

那么我们对所包含的边都跑一遍强连通分量

复杂度线性


https://acm.hdu.edu.cn/showproblem.php?pid=7443

我们要确定mex的最大值,

就是使0-x尽量大

使用二分答案判断一条链上能否达到一个mex值

每个连通块内部就不会链接到其他点

开两维,需要办掉一些区域

我们化掉一些矩形,考虑删掉某个点所在的子树

那么还有一种情况,即连续几个点

使用线段树维护矩形面积并

对于每个图,连通块数量不会很多

那么树的数量就是n^2级别

(后面没听懂先不抄了。。)


https://acm.hdu.edu.cn/showproblem.php?pid=7436

使用线段树分治)????

当一个东西加入容易,

删除困难,

但可以撤销

那么线段树分治就很套路

我们将时间建一颗线段树

那么某条边就是在某段时间内存在

使用并查集加边

要满足撤销,就要使用按秩并查集

考虑是否是叶子,

递归到叶子时,

跟中要加的所有东西都加入了

时间认为是t,那么加到线段书上,应该是nlogt

总复杂度是O(fnlogt)

使用类似懒标记的方法,

对于每个叶子节点,

设置懒标记

考虑加边和减边


https://www.luogu.com.cn/problem/AT_abc363_g

如何在有修改的前提下进行操作

将题目看成类似费用流的关系

每一个点代表一天

发现一天只做一个工作,那么权值就是Ti

每次加一条边

维护整个费用流的图

套一个线段树分治

在n+q范围加边

最终出现边和反向边

所以一般情况下

每一个点,

都会有对应的一条边

向右有一定数量的反向边

往前流或往后流

我们去所有方案中权值的最大值

每次加一次边之需要一次增广

那么考虑维护增广结果

使用线段树维护

发现向后流的边会有反向边

能够从前面流的边,

一定会有反向的最大值

这样连边直到最后,只要加一减一就可以维护了


网络流学习笔记

最大流算法(Ford-Fulerson)

  1. 建立残差图(即残量网络图),初始化容量

  2. 在可以找到增广路的前提下循环:

    a. 寻找增广路
    b. 找到最小容量x
    c. 更新残量网络上容量
    d. 添加反向边

以下是Ford-Fulerson的不同实现

Edmonds-Karp

  1. bfs寻找增广路

  2. 计算最小边,更新边权,添加反向边

  3. 得到新增广图

struct MF {
  struct edge {
    int v, nxt, cap, flow;
  } e[N];

  int fir[N], cnt = 0;

  int n, S, T;
  ll maxflow = 0;
  int dep[N], cur[N];

  void init() {
    memset(fir, -1, sizeof fir);
    cnt = 0;
  }

  void addedge(int u, int v, int w) {
    e[cnt] = {v, fir[u], w, 0};
    fir[u] = cnt++;
    e[cnt] = {u, fir[v], 0, 0};
    fir[v] = cnt++;
  }

  bool bfs() {
    queue<int> q;
    memset(dep, 0, sizeof(int) * (n + 1));

    dep[S] = 1;
    q.push(S);
    while (q.size()) {
      int u = q.front();
      q.pop();
      for (int i = fir[u]; ~i; i = e[i].nxt) {
        int v = e[i].v;
        if ((!dep[v]) && (e[i].cap > e[i].flow)) {
          dep[v] = dep[u] + 1;
          q.push(v);
        }
      }
    }
    return dep[T];
  }

  int dfs(int u, int flow) {
    if ((u == T) || (!flow)) return flow;

    int ret = 0;
    for (int& i = cur[u]; ~i; i = e[i].nxt) {
      int v = e[i].v, d;
      if ((dep[v] == dep[u] + 1) &&
          (d = dfs(v, min(flow - ret, e[i].cap - e[i].flow)))) {
        ret += d;
        e[i].flow += d;
        e[i ^ 1].flow -= d;
        if (ret == flow) return ret;
      }
    }
    return ret;
  }

  void dinic() {
    while (bfs()) {
      memcpy(cur, fir, sizeof(int) * (n + 1));
      maxflow += dfs(S, INF);
    }
  }
} mf;
  • 22
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值