zoukankan      html  css  js  c++  java
  • 好题思路集汇

    慢慢地发现每次打题解会很麻烦而且费时间,这篇博客留作思路汇总,给自己警醒。

    游戏 (模拟36)

      某天T3,思路难点在于把每个状态的点区分出来,也就是拆点,然后在给不同状态的点连边,进行最短路操作。

      对于图上需要操作走动的点来说,往往不同的状态之间转移会很困难,在实现过程中也很难实现,不如把不同状态的点拆成多个状态互不影响的点,在分别考虑其转移条件,然后在区分对待,这样会使不同状态之间的考虑化简,之后考虑好状态之间的转移就可以了。

      题目思路挺不错的。

    影子 (模拟41)

      并查集+lca找两点距离。

      这题的并查集用的很巧妙,将点权从大到小排序,用并查集维护点集,点集中点权最小的点为当前枚举到的点。

      然后有一个很巧妙的思路,维护当前点集的直径和该直径对应的两个端点,当我们搜到合并两个点集的时候,将端点两两结合,有四种情况,在加上两个点集本身的直径取最大,就是在当前点的最优答案。新点集的直径的端点一定属于上述四个端点之一,正确性可以反证法证明。

      注意点集一定要合并,情况要考虑全。

    夜莺与玫瑰 (模拟41)

      莫比乌斯函数中的mu函数的妙用,4维到1维的优化,用到的等差数列求和。

    玫瑰花精 (模拟41)

      线段树在序列上的操作,维护了一些神奇的东西。

      l,r,mid,p,l维护最左边的鸟的位置,r维护最右边的鸟的位置,mid维护距离两只相邻鸟的最长距离,p维护mid值的位置。

      查询只查询根节点1的p值即可,注意与1,p,n的比较。

      删点和插点操作相似,注意多种情况的枚举,也就是左儿子最右边的鸟,右儿子最左边的鸟的关系。

     C (模拟43)

      线段树+贪心+三分。

      这几天的线段树维护一个特定的区间的题挺多的,加上模拟42的T2,可以看一看。

      线段树维护的方法:先保证左端点一定满足条件,再把右端点插进去,找其中的最大or最小的右端点,实现贪心。

      这道题还用到了三分,因为答案关于选特殊的个数是单谷函数。

      至于贪心的证明,还需要再自己考虑考虑。

    F (模拟44)

      线段树优化dp。

      这道题dp的思路还不错,毕竟考试的时候想了一个性能比较差的dp。

      然后就是一个线段树优化了。

      其实就是优化掉内层循环,找一下循环里面的性质,这道题是其中的不变量$dp_i-i$和$dp_i+i$,和给整个区间加上的相同的值。

      可以拓展到更多的情况,比如区间减,区间赋值,单点查询,区间查询等。

      具体依据具体性质而定。

    kill (模拟45)

      二分+贪心。

      其实二分不难看出来,但是考场上真的有些懵了,二分没看出来,打了个傻逼set。

      然后排序,贪心就行了。

      我们要使每个人的花费最优,而我们在排序的基础上,枚举每个人所在的位置,从左到右找第一个符合条件的位置,因为后面的所有人都不会将我找到的这个位置左边的点作为最优点。

      贪心即可,还有一个小性质,每个小怪兽的固定花费都是不变的,虽然没啥用,但是也是需要积累一下的。

    beauty (模拟45)

      题目转化问题很惊喜,自己在转化题目的能力方面做的还是太差了。

      根据题意,很容易想到去找链找最大,但是这显然复杂度不对,然后找性质。

      其实吧,就离正解不远了,但是自己没能突破这一哆嗦。

      当自己卡在某一个思路的时候,想想突破,另辟蹊径,找一下意想不到的地方。

      这道题在找(kan)了n年(bian)性(ti)质(jie)后,会惊喜的发现,可以把每个边对答案的贡献单独拿出来算。

      然后这道题就解决了。

    set (模拟46)

      前缀和。

      这道题前缀和不是很难,但是它要求对前缀和的理解和对模的意义有较高要求,总之考试的时候没想到。

      A掉简单想到难。其实主要的还是一个在模n意义下最多只有n个不同的取值,然后就可以断定,一定有一个连续的区间符合条件,然后前缀和就行了。

    read (模拟46)

      思路不难但是打死想不到系列。

      性质一:一个序列里最多有一种元素是整个序列的一半以上,减到合法后不会有新的元素种类不合法,可以简单证明。

      然后乱搞就行了,题目卡的地方就是不让开数组,这就需要我们找一个不合法的元素。

      然后“所以我们用两个变量 id, cnt, cnt 初始为 0. 然后生成每一个 A[i], 如果 cnt==0, 那么就令 id=A[i], cnt=1, 否则如果 id==A[i], 则 cnt++, 如不等于 , cnt--. 最后只要再扫一遍求出 id 的出现次数即可 .
      因为如果有书超过 (N+1)/2, 那么就以为这它比其他所有书的和都多 , 那么 cnt 怎么减都不会小于0, 如果没有那 id 随便是哪个都没有关系了 . 最后再求这种书要减少多少个就可以了 .”

      题解抄下来了。

    蔬菜 (模拟50)

      二维莫队。

      这道题其实也不是很难,但是考场上确实没想到,一个比较板子的东西。

      莫队的计算也比较简单,总之练了一下莫队。

    联盟 (模拟50)

      树的直径综合。

      首先性质,断边肯定在直径上。

      然后就是各种求树的直径的方法了,两遍Dfs求直径,还有就是dp求直径,dp的方法适用与有根树的直径。

    u (模拟53)

      矩阵上的差分,挺好的一道题。

      自己的一点理解吧,这个差分利用了题中所说的下直角三角型的特性,差分的链只会沿两种路线走,我们可以分别维护这两种走法,然后两个数组分别差分,然后把两个差分数组合并起来,在扫一边整个矩阵。

      差分好题。

    v (模拟53)

      记忆化搜索+状压$DP$。

      位运算一定要用好,尽量适合自己的下一步转移。

      复杂度是可以证明的,每个状态只会被枚举一次,复杂度不是很高。

      记忆化状态,然后用$HASH$表存起来,注意$HASH$表查询的限制条件,如果限制条件很多的话,$HASH$就不怎么适用了,$HASH$数我觉得$19260817$就不错。

      记忆化一定要好好分析复杂度,不然很容易写挂。

    w (模拟53)

      树形DP好题,很大程度上在于$DP$的定义和转移。

      不难看出题目的限制在于2边是否要翻转,一个小性质就是每条需要翻转的边只会被翻转一次,贡献就只是2边的贡献就行了。

      $f_{0/1,i}$表示点i是否向上连一条边,$w_{0/1}$表示他的儿子是否有一条边与父亲相连,也就是儿子中有奇数条边与当前点相连(其他的偶数条边可以经过当前点而不会对答案产生贡献),还能从中发现,我的链的条数就是奇点(有奇数条需要翻转的与该点相连的边的点)的个数/2。

      $f$和$w$都是二元组,第一维是当前点的子树中最小的奇点的个数,第二维是当前状态下的最小的翻转长度。

      转移用$w$转移$f$,转移不是很难想,重要的还是$DP$定义,自己$DP$定义能力还是不够。

      这道题转移挺麻烦的,而我挺懒的,咋办呢。

     1 #include<cstdio>
     2 #include<iostream>
     3 #define LL long long
     4 #define HZOI std
     5 using namespace HZOI;
     6 const int N=1e5+3;
     7 const int INF=0x3f3f3f3f;
     8 int n;
     9 int tt,first[N],vv[N<<1],nx[N<<1],ww[2][N<<1];
    10 int co[N],go[N],ans[2];
    11 pair<int,int> dp[2][N];
    12 void Dfs(int ,int );
    13 inline void Add(int ,int ,int ,int );
    14 inline int read();
    15 int main()
    16 {
    17     n=read();
    18     tt=1;
    19     for (int i=1,a,b,c,d; i<n; ++i) 
    20     {
    21         a=read(),b=read(),c=read(),d=read();
    22         Add(a,b,c,d),Add(b,a,c,d);
    23     }
    24     Dfs(1,0);
    25     printf("%d %d
    ",dp[0][1].first/2,dp[0][1].second);
    26     return 0;
    27 }
    28 void Dfs(int k,int father)
    29 {
    30     pair<int,int> w[2];
    31     w[0]=make_pair(0,0);
    32     w[1]=make_pair(INF,INF);
    33     for (int i=first[k]; i; i=nx[i])
    34     {
    35         int ver=vv[i];
    36         if (ver==father) continue;
    37         co[ver]=ww[0][i],go[ver]=ww[1][i];
    38         Dfs(ver,k);
    39         pair<LL,LL> temp0,temp1;
    40         temp0=w[0],temp1=w[1];
    41         w[0]=min(make_pair(dp[1][ver].first+temp1.first,dp[1][ver].second+temp1.second),
    42                     make_pair(dp[0][ver].first+temp0.first,dp[0][ver].second+temp0.second));
    43         w[1]=min(make_pair(dp[0][ver].first+temp1.first,dp[0][ver].second+temp1.second),
    44                     make_pair(dp[1][ver].first+temp0.first,dp[1][ver].second+temp0.second));
    45     }
    46     if (go[k]!=2 && co[k]!=go[k])
    47     {
    48         dp[0][k]=make_pair(INF,INF);
    49         dp[1][k]=min(make_pair(w[1].first,w[1].second+1),make_pair(w[0].first+1,w[0].second+1));
    50     }
    51     if (co[k]==go[k])
    52     {
    53         dp[1][k]=make_pair(INF,INF);
    54         dp[0][k]=min(make_pair(w[1].first+1,w[1].second),w[0]);
    55     }
    56     if (go[k]==2)
    57     {
    58         dp[0][k]=min(make_pair(w[1].first+1,w[1].second),w[0]);
    59         dp[1][k]=min(make_pair(w[1].first,w[1].second+1),make_pair(w[0].first+1,w[0].second+1));
    60     }
    61     return ;
    62 }
    63 inline void Add(int u,int v,int color,int goal)
    64 {
    65     vv[++tt]=v,nx[tt]=first[u],first[u]=tt,ww[0][tt]=color,ww[1][tt]=goal;
    66 }
    67 inline int read()
    68 {
    69     int nn=0; char cc=getchar();
    70     while (cc<'0' || cc>'9') cc=getchar();
    71     while (cc>='0' && cc<='9') nn=(nn<<3)+(nn<<1)+(cc^48),cc=getchar();
    72     return nn;
    73 }
    w

      溜了。

    y (模拟54)

      状压$DP$。

      一道好题,将我的状压思路开阔了一点。

      将通常的枚举起点或终点的思路转化成枚举中间点,有利于减少状态转移。

      把状压的状态一分为二,形成两个状压,最后拼凑成一个完整的状态。

      其中要注意状态的完整和始末状态。

    x国的军队 (模拟b「六人AK」)

      牛逼题。

      要剩下的人最少,把b-a从大到小排序。

    排列组合 (模拟b「六人AK」)

      牛逼题,打表找规律(我都不知道自己咋$A$的)。

      正解:把$C_n^i$换成$C_n^{n-i}$,就会发现这是把一个大小为$2n$的集合里,在前$n$个选$i$个,后$n$个选$n-i$个,然后$Σ$,就是$C_{2n}^n$了。

    回文 (模拟b「六人AK」)

      牛逼题,前缀和。

      注意一下转移的方向,一定要从有值的地方转移到无值的地方,这个要记一下。

     Equation (模拟56)

      $DFS$序+线段树+分类讨论。

      式子很好化,都转化成有$x_1$的形式,然后分类讨论就行了。

      考试的时候脑子有点不好使,本来是前缀和,区间修改的写成单点修改了,然后暴力分都没拿到。

      这个暴力思路就是$DFS$暴力改,然后想一下优化这个过程。

      我们发现每次修改的都是一个子树中的信息,这样的话就可以想到$DFS$序优化,把树上信息转化成链上,然后用线段树维护,区间修改即可。

      不过这样会T。。SB卡常题。。

      然后把线段树换成树状数组差分即可。

    嘟嘟嘟 (模拟60)

      约瑟夫问题,优化循环次数。

      考虑二分,二分出$cnt$,表示经过了$cnt+1$次操作,$ans+(cnt+1)*m>=i+cnt$,二分出答案就好了。

      时间复杂度是调和级数级别的。

      其实$cnt$可以直接求出来。。

    天才绅士少女助手克里斯蒂娜 (模拟60)

      推式子,数据结构板子题。

      推式子可以考虑容斥的思想,总方案减去不合法方案,还有就是可以将式子中的$i,j$瞎转化一下,同种变量的下标尽量相同,更有利于推导和对式子的理解,然后瞎搞就行了。

      线段树的话,懒标记都不用,裸的单点修改区间查询。

    Tree (模拟62)

      结论题,答案为边权和相加。

      感性理解一下,没条边至少有一个贡献,而当经过的边最少时,也就是每条边只经过一次时,结果最小。

      证明一下:我们在整个树中选一条边权最大的边,每次类似于$BFS$在边的两端扩展,每次走向次大边,这样走下去等遍历完整颗树,答案为最优也就是边权和。

      证毕。

    trade (模拟64)

      反悔贪心,堆维护一下就好了,注意加入元素的含义。

    sum (模拟64)

      公式推导,莫队。

      最主要的是公式,手玩一下会发现上一行对当前行会产生2倍的贡献,画一个杨辉三角就出来了。

      递推式:$S_{n,m}=S_{n,m-1}+C_n^m$

          $S_{n,m}=2*S_{n-1,m}-C_{n-1}^m$

    幻魔皇 (模拟67)

      又是一个神仙打表题。

      树很有特点,有很多树是相同的,然后可以找其中的规律。

      对于$LCA$为黑点跟白点的情况我们可以分开考虑,然后直接上$fib$就好了,主要还是找这种图的规律,合并相同情况,不同情况分开讨论,想到这些以后,$fib$的使用不算很难。

  • 相关阅读:
    洛谷P5979 [PA2014]Druzyny
    洛谷P5592 美德的讲坛
    BZOJ4231 回忆树
    Python爬虫〇二———从几个简单的爬虫开始
    Flink实例(115):自定义时间和窗口的操作符(十四)窗口操作符(四)触发器(Triggers) (二)
    商业化数据分析师(三十二):平台商品画像实战项目(三)购物篮分析
    商业化数据分析师(三十一):平台商品画像实战项目(二)如何构建商品画像-- 以移动电源为例
    商业化数据分析师(三十):平台商品画像实战项目(一)简介
    商业化数据分析师(二十九):平台用户画像实战项目(二)如何构建平台用户的用户画像
    商业化数据分析师(二十八):平台用户画像实战项目(一)什么是用户画像体系以及商户用户画像和平台用户画像的区别
  • 原文地址:https://www.cnblogs.com/LH-Xuanluo/p/11468818.html
Copyright © 2011-2022 走看看