zoukankan      html  css  js  c++  java
  • 2017多校Round3(hdu6056~hdu6066)

    补题进度:7/11

    1001

    待填坑

    1002

    待填坑

    1003(set)

    题意:

    给定长度为n(n<=5e5)的数组(是n的一个排列)和一个整数k(k<=80),f[l,r]定义为区间[l,r]内的第k大的数,求所有区间的f值的和

    分析:

    倒过来考虑,考虑每个数a[i]对答案有多少贡献

    将n个数字从大到小依次插入对应位置,已经插入的当作障碍点(可以用set来维护)

    那么对于一个i,可以枚举其左边有x个右边有k-x个去统计答案,因为k<=80,所以是OK的

    注意边界情况

    时间复杂度O(n(k+logn))

    1004(01Trie树)

    题意:

    给一个长度为n(n<=5e5)的数组,问有多少个三元组满足

    分析:

    异或统计问题肯定想到01Trie树

    最简单的想法就是我去枚举j,左右两边分别弄一个01Trie树,但仔细一想发现这样无法统计答案

    我们发现一个规律,如果A[i]和A[k]的某一位不同(从高到低),那么A[j]这一位的值是固定的,一定和A[i]相同,和A[k]相反

    实际上我们只需要将所有数从后往前加,即枚举i,去统计答案

    对于一个确定的A[i],在Trie树上面爬,枚举A[i]和A[k]第一个不同位

    ——对于当前位A[k]与A[i]相同,继续向下走

    ——对于当前位A[k]与A[i]不同,那么就统计答案,这里我们可以确定该位A[j]的值为x,那么我们应该怎样求这样的A[j]的个数呢?

    这里我们可以预处理,sum[i][j][0/1]表示前i个数中,第j位是0/1的数字有多少个

    s[u]表示以节点u下面的所有单词节点作为A[k],前面一共有多少个j满足A[k]的这一位不同,这里可以通过倒着枚举i将A[i]插入的过程中,借助sum来完成

    但是注意sum表示的前缀和,对于一个给定的i,我们Trie树节点的s[u]存的是前面所有的j的个数,那么j<i的是要删除的,所以统计答案的时候要减去当前这个子树底下k的个数*i前面的那些满足条件的j的个数

     1 void insert(int p,int x)
     2 {
     3     int u=root;
     4     for(int i=maxw;i>=0;--i)
     5     {
     6         int d=((bit[i]&x)>0);
     7         if(!ch[u][d]) ch[u][d]=++len;
     8         u=ch[u][d];
     9         ++num[u];
    10         s[u]+=sum[p-1][i][d^1];
    11     }
    12 }
    13 
    14 
    15 ans=0;
    16 for(int i=n;i>=1;--i)
    17 {
    18     int u=root;
    19     for(int h=maxw;h>=0;--h)
    20     {
    21         int d=((bit[h]&a[i])>0);
    22          if(ch[u][d^1])
    23             ans+=s[ch[u][d^1]]-1LL*sum[i][h][d]*num[ch[u][d^1]];
    24          if(!ch[u][d]) break;
    25          u=ch[u][d];
    26      }
    27      insert(i,a[i]);
    28 }    
    View Code

    1005(贪心)

    题意:

    给出一个n(n<=1000000)个的点的树,需要你将2~n分成k组

    每一组的价值是{1}∪{这个组里所有点}这个集合里所有点组成的最小斯坦纳树的边权和

    现在要让所有组的价值和最大

    分析:

    数据范围相当于提示你要用O(n)的方法

    我们给2~n做编号1~k,编号相同的点分到一组

    假设分块已经固定了,我们来思考如何统计答案

    我们来考察每条边(u,fa[u])对答案的贡献

    这个贡献一定是以u为根的子树中不同编号的种数

    既然要让最后的总结果最大,我们肯定希望每条边(u,fa[u])对答案的贡献越大越好

    即以u为根的子树中不同编号的点的个数越多越好

    如果size[u]<=k,那就让它们编号互异,贡献个数是size[u]个

    如果size[u]>k,那就让它们k个编号互异,然后剩下的构造相同的,贡献个数是k个

    这只是我们的理论答案上界,不过手画画几组样例发现确实可以构造出这样的解,所以理论答案上界就是最后的答案

    1006(NTT)

    题意:

    化简一个式子

    分析:

    无脑化简,到最后发现就是一个卷积

    直接NTT

    此处的卷积不再是i+j=k,而是i-j=k,将减法看成加一个负下标,错位处理一下就可以了,仍旧是基础的卷积

    1007

    待填坑

    1008(找规律)

    题意:

    分析:

    比赛时候找规律,发现最后结果就是n^k,快速幂一搞就行了

    说一下为啥是n^k

    一个整数x一定可以写成a*b^2 其中a是无平方因子数,即|μ(a)|=1

    那么题目中这个式子相当于在枚举a,然后计算有多少个b

    由于任意一个整数都可以写成这种式子,所以这种计算方式包含了1~n^k内所有的整数

    所以答案就是n^k

    1009

    待填坑

    1010(决策单调性优化DP)

    题意:

    给出n个点的树(n<=3e5)以及n的一个排列,现在你要将这个长度为n的排列分成k组(k<=3e5,n*k<=3e5),让所有组的价值和最小

    一组的价值和是这组中所有点在树上的lca的深度

    分析:

    很典型的一个分段dp

    可以很简单写出O(n^2k)的dp

    计算价值可以通过O(1)来计算,因为a1,a2,...,am的lca不需要每次算出前缀的lca和后面一位做lca,这m个数的lca一定是lca(a1,a2) lca(a2,a3) ... lca(am-1,am)中深度最小的,于是就可以提前搞一个rmq

    然后显然这种问题满足决策单调性,所以时间复杂度O(nklogn),这就能过了

    还有一种更优秀的dp方法

    我们把所有相邻位置的lca全部写出来,其实就是让我们挑选k个位置作为“关键位置”,这k个位置对结果贡献,其它位置对结果不贡献

    dp[i][j]仍旧表示前i个数中挑出j个数作为“关键位置”的最小代价

    ①当前位置不作为“关键位置” dp[i][j]=dp[i-1][j]

    ②当前位置作为一个新的“关键位置" dp[i][j]=dp[i-2][j-1]+lca(a[i-1],a[i])

    还要注意一点,就是可能某个位置单独作为一块

    ③dp[i][j]=dp[i-1][j-1]+a[i]

    所有的取min就行了

    时间复杂度O(nk)

    1011(模拟)

  • 相关阅读:
    ORM框架
    js获取浏览器和元素对象的尺寸
    js中的兼容问题
    JS页面上的流氓广告功能
    JS计算1到10的每一个数字的阶乘之和
    JS中 有一个棋盘,有64个方格,在第一个方格里面放1粒芝麻重量是0.00001kg,第二个里面放2粒,第三个里面放4,棋盘上放的所有芝麻的重量
    JS中99乘法表
    JS 中计算 1
    JS中判断一个数是否为质数
    JS水仙花数
  • 原文地址:https://www.cnblogs.com/wmrv587/p/7295663.html
Copyright © 2011-2022 走看看