高二一调(20190614)

T1:Censoring

  和以前kmp一样的一道题,只是改成了多个串需要AC自动机

  用一个栈维护当前字符串,匹配上了就暴力弹栈,并将指针回溯,复杂度O(n+m)

  这题考试的时候不知道怎么把栈给否掉了,用了个玄学方法记录,只干出来13分

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define null NULL
using namespace std;
struct node{
    node *fi,*ch[26];
    int c;
    node (){
        fi=null;c=0;
        memset(ch,null,sizeof(ch));
    }
}*root=new node();
char a[2002][100002];int le[2002];
short s[200];
void insert(int x){
    node *now=root;int len=le[x];
    for(int i=1;i<=len;i++){
        int in=s[a[x][i]];
        if(now->ch[in]==null) now->ch[in]=new node();
        now=now->ch[in];
    }
    now->c=x;
}
void getfail(){
    queue<node*>q;
    for(int i=0;i<26;i++)
      if(root->ch[i]!=null){
          root->ch[i]->fi=root;
          q.push(root->ch[i]);
      }
      else root->ch[i]=root;
    while(!q.empty()){
        node *now=q.front();q.pop();
        for(int i=0;i<26;i++)
          if(now->ch[i]!=null){
              now->ch[i]->fi=now->fi->ch[i];
              q.push(now->ch[i]);
          }
          else now->ch[i]=now->fi->ch[i];
    }
}
node *last[100002];
int top,sol[100002];char sta[100002];
void query(){
    node *now=root;int len=le[0],del=0;
    for(int i=1;i<=len;i++){
        if(now==null) now=root;
        sta[++top]=a[0][i];last[top]=now;
        int out=s[a[0][i]];
        now=now->ch[out];
        if(now->c){
            top-=le[now->c];
            now=last[top+1];
        }
    }
}
int main(){
    for(int i=‘a‘;i<=‘z‘;i++) s[i]=i-‘a‘;
    for(int i=‘A‘;i<=‘Z‘;i++) s[i]=i-‘A‘;
    scanf("%s",a[0]+1);le[0]=strlen(a[0]+1);
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",a[i]+1);
        le[i]=strlen(a[i]+1);
        insert(i);
    }
    getfail();
    query();
    for(int i=1;i<=top;i++)
      putchar(sta[i]);
    return 0;
}

AC代码

T2:记忆的轮廓

  概率期望,考试时候直接弃了(主要是无良老师数据范围没给)

  50%:数据n==p,则不需要考虑存档,首先设d[i]表示i的儿子数。设g[i]表示对于一个错误节点i,期望走多少步会读档。那么

    g[i]=1+1/d[i]*∑{g[j]}其中j是i的儿子。

  接下来我们倒着递推:f[i]=1+1/d[i]*f[i+1]+1/d[i]*∑{g[j]+f[i]}[j是i的错误儿子]

  移项得:f[i]=d[i]+f[i+1]+Σg[j][j是i的错误儿子] 复杂度O(m)

  70%:我们设dp,f[i,j]表示当前存档点为i,还剩j次存档机会。

  首先我们需要预处理一个a[i,j],表示存档点为i,从i开始走到正确节点j的期望步数(中间不能存档)。

  显然有边界条件a[i,i]=0。对于i<j,可以列出递推式:

  a[i,j]=a[i,j-1]+1+1/d[j-1]*∑{g[k]+a[i,j]}[k是j-1的错误儿子]

  移项得a[i,j]=a[i,j-1]*d[j-1]+d[j-1]+Σg[k][k是j-1的错误儿子]

  则f[i][k]=min(f[j][k-1]+a[i][j]),答案f[1][p-1]

  复杂度O(pn^2)

100%:优化方向1:我们观察a数组,发现有a[i,j]<a[i,j+1],a[i-1][j]>a[i][j]

那么我们可以用单调队列优化,用两维的单调队列(当前和上一次)每次把所有f[i][k]插入

    每次查询的时候若队头que[st].dp+a[i][que[st].at]>=que[st+1].dp+a[i][que[st+1].at]||que[st].at<=i就出队

    然后理论上我们还需要二分来找到两个函数交点

    但是我没找它就过了......

    复杂度O(pn)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#define re register
using namespace std;
struct node{
    int at;
    double dp;
}que[2000][2];
double g[2005],f[2005][705],d[2005],a[2005][2005];
int to[2000][5],st[2],ed[2],now;
void dfs(int u){
    int d=to[u][0];
    g[u]=1;
    for(int i=1;i<=d;i++){
        dfs(to[u][i]);
        g[u]+=g[to[u][i]]/d;
    }
}
int main(){
    int T,n,m,p,x,y;
    scanf("%d",&T);
    while(T--){
        memset(f,127,sizeof(f));memset(a,0,sizeof(a));memset(to,0,sizeof(to));
        scanf("%d%d%d",&n,&m,&p);p--;
        for(int i=1;i<=m-n;i++){
            scanf("%d%d",&x,&y);
            to[x][++to[x][0]]=y;
        }
        for(int i=1;i<=n-1;i++){
            d[i]=to[i][0];g[i]=0;
            for(int j=1;j<=d[i];j++){
                dfs(to[i][j]);
                g[i]+=g[to[i][j]];
            }
            d[i]+=1;
        }
        for(int i=1;i<=n-1;i++)
            for(int j=i+1;j<=n;j++)
              a[i][j]=a[i][j-1]*d[j-1]+g[j-1]+d[j-1];
        st[now]=1;ed[now]=0;
        que[++ed[now]][now].dp=0;
        que[ed[now]][now].at=n;
        for(int k=1;k<=p;k++){
            now^=1;
            st[now]=1;ed[now]=0;

            for(int i=1;i<=n-1;i++){
                while(st[now^1]<ed[now^1]&&(que[st[now^1]][now^1].at<=i||que[st[now^1]][now^1].dp+a[i][que[st[now^1]][now^1].at]>=que[st[now^1]+1][now^1].dp+a[i][que[st[now^1]+1][now^1].at])) st[now^1]++;
                f[i][k]=que[st[now^1]][now^1].dp+a[i][que[st[now^1]][now^1].at];
            }
            for(int i=1;i<=n-1;i++) que[++ed[now]][now].dp=f[i][k],que[ed[now]][now].at=i;
            que[++ed[now]][now].dp=0;que[ed[now]][now].at=n;
        }
        printf("%.4lf\n",f[1][p]);
    }
    return 0;
}

AC代码

  优化方向2:观察a数组,可以看到它是恐怖的增长的

我们来估计答案的上界,考虑一种可行方案,每n/p个正确节点就设立一次存档位置,那么答案最大是多少呢?考虑最坏情况,观

  察a的转移,应该每变换一次存档点,

设s[i]=Σg[j]大约需要3^(n/p)s[i]+3(n/p-1)*s[i+1]+3^(n/p-2)*s[i+2]+……因为最多m个节点,s的上限是1500(实际上也远远达不

到)

  那么其实,针对答案不会特别大,a的增长又很恐怖,我们还可以思考对70%的算法优化。那就是设定一个常数step,每次转移最

  多从距当前step步远的位置转移过来。step取40多基本不会有问题了,因为a的下界已经是2^40了,而答案的上界远远没有 

     达到,经过精确计算还可以再把step调小一点。

  复杂度O(np log ans)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#define re register
using namespace std;
struct node{
    int at;
    double dp;
};
deque<node>q;
double g[2005],f[2005][705],d[2005],a[2005][2005];
int to[2000][5];
void dfs(int u){
    int d=to[u][0];
    g[u]=1;
    for(int i=1;i<=d;i++){
        dfs(to[u][i]);
        g[u]+=g[to[u][i]]/d;
    }
}
int main(){
    int T,n,m,p,x,y;
    scanf("%d",&T);
    while(T--){
        memset(f,127,sizeof(f));memset(a,0,sizeof(a));memset(to,0,sizeof(to));
        scanf("%d%d%d",&n,&m,&p);p--;
        for(int i=1;i<=m-n;i++){
            scanf("%d%d",&x,&y);
            to[x][++to[x][0]]=y;
        }
        for(int i=1;i<=n-1;i++){
            d[i]=to[i][0];g[i]=0;
            for(int j=1;j<=d[i];j++){
                dfs(to[i][j]);
                g[i]+=g[to[i][j]];
            }
            d[i]+=1;
        }
        for(int i=1;i<=n-1;i++)
            for(int j=i+1;j<=n;j++)
              a[i][j]=a[i][j-1]*d[j-1]+g[j-1]+d[j-1];
        f[n][0]=0;
        for(int k=1;k<=p;k++)
          for(int i=n-1;i>=1;i--)
            for(int j=i+1;j<=n&&j-i<=40;j++)
            {
                f[i][k]=min(f[i][k],f[j][k-1]+a[i][j]);
                if(f[j+1][k-1]>f[j][k-1]) break;
            }
        printf("%.4lf\n",f[1][p]);
    }
    return 0;
}

AC代码

T3:动态开点+权值线段树合并+树上差分

  考试时候想到了没敢打,主要没分析好空间复杂度

  对每个点开权值线段树,离不离散都行

  复杂度时间,空间都是O(nlogn)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define re register
#define L ls[k]
#define R rs[k]
#define lc ls[k],l,mid
#define rc rs[k],mid+1,r
using namespace std;
inline int read(){
    re int a=0;re char ch=getchar();
    while(ch<‘0‘||ch>‘9‘) ch=getchar();
    while(ch>=‘0‘&&ch<=‘9‘) a=(a<<3)+(a<<1)+ch-‘0‘,ch=getchar();
    return a;
}
int rt[100005],ans[100005],ls[5000000],rs[5000000],da[5000000],d[100005],f[100005][20],fr[100005],to[200005],la[200005],cnt,num,is[100005],tot;
inline void add(int x,int y){
    to[++num]=y;
    la[num]=fr[x];
    fr[x]=num;
}
void dfs(int u,int fa){
    for(int i=1;(1<<i)<=d[u];i++) f[u][i]=f[f[u][i-1]][i-1];
    for(int i=fr[u];i;i=la[i])
      if(to[i]!=fa){
           d[to[i]]=d[u]+1;f[to[i]][0]=u;
           dfs(to[i],u);
      }
}
int getlca(int a,int b){
    if(d[a]<d[b]) swap(a,b);
    for(int i=18;i>=0;i--)
        if(d[a]-(1<<i)>=d[b]) a=f[a][i];
    if(a==b) return a;
    for(int i=18;i>=0;i--)
        if(f[a][i]!=f[b][i]) a=f[a][i],b=f[b][i];
    return f[a][0];
}
void insert(int &k,int l,int r,int x,int y){
    if(!k) k=++cnt;
    if(l==r){
        da[k]+=y;
        return;
    }
    re int mid=(l+r)>>1;
    if(x<=mid) insert(lc,x,y);
    else insert(rc,x,y);
    da[k]=max(da[L],da[R]);
}
int merge(int x,int y,int l,int r){
    if(!x||!y) return x+y;
    if(l==r){
        da[x]+=da[y];
        return x;
    }
    re int mid=(l+r)>>1;
    ls[x]=merge(ls[x],ls[y],l,mid);
    rs[x]=merge(rs[x],rs[y],mid+1,r);
    da[x]=max(da[ls[x]],da[rs[x]]);
    return x;
}
int query(int k,int l,int r){
    if(!da[k]||!k) return 0;
    if(l==r) return l;
    re int mid=(l+r)>>1;
    if(da[L]>=da[R]) return query(lc);
    else return query(rc);
}
void dfss(int u,int fa){
    for(int i=fr[u];i;i=la[i])
      if(to[i]!=fa){
           dfss(to[i],u);
           rt[u]=merge(rt[u],rt[to[i]],1,tot);
      }
    ans[u]=is[query(rt[u],1,tot)];
}
struct node{
    int x,y,z;
}Q[100005];
inline int as(node x,node y){
    return x.z<y.z;
}
int main(){
    int x,y,z,n=read(),m=read();
    for(int i=1;i<n;i++){
        x=read();y=read();
        add(x,y);add(y,x);
    }
    d[1]=1;
    dfs(1,0);
    for(int i=1;i<=m;i++)
      Q[i].x=read(),Q[i].y=read(),Q[i].z=read();
    sort(Q+1,Q+m+1,as);
    for(int i=1;i<=m;i++){
        if(Q[i].z!=Q[i+1].z) is[++tot]=Q[i].z,Q[i].z=tot;
        else Q[i].z=tot+1;
    }
    for(int i=1;i<=m;i++){
        int lca=getlca(Q[i].x,Q[i].y);
        insert(rt[Q[i].x],1,tot,Q[i].z,1);
        insert(rt[Q[i].y],1,tot,Q[i].z,1);
        insert(rt[lca],1,tot,Q[i].z,-1);
        insert(rt[f[lca][0]],1,tot,Q[i].z,-1);
    }
    dfss(1,0);
    for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
    return 0;
}

AC代码

这次考试总体状态还可以,就是对于一些东西想的不深入,没有透彻理解

主要就是第一题没有拿到应该的分,当时感觉是一道水题没有当回事,码的时候没有注意细节,自己编了几个样例过了就以为稳了

以后对于水题一定得仔细,否则别的题得分再高也没用

以上。

原文地址:https://www.cnblogs.com/mikufun-hzoi-cpp/p/11038262.html

时间: 2024-10-10 21:37:16

高二一调(20190614)的相关文章

JVM原理讲解和调优

一.什么是JVM JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的. Java语言的一个非常重要的特点就是与平台的无关性.而使用Java虚拟机是实现这一特点的关键.一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码.而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译.Java语言使用Java虚拟机屏蔽了与具体平台相关的信息

spark性能调优之资源调优

转https://tech.meituan.com/spark-tuning-basic.html spark作业原理 使用spark-submit提交一个Spark作业之后,这个作业就会启动一个对应的Driver进程.根据你使用的部署模式(deploy-mode)不同,Driver进程可能在本地启动,也可能在集群中某个工作节点上启动.Driver进程本身会根据我们设置的参数,占有一定数量的内存和CPU core.而Driver进程要做的第一件事情,就是向集群管理器(可以是Spark Stand

mysql性能调优与架构设计笔记

1.mysql基本介绍 mysql支持多线程高并发的关系型数据库; 数据库存储引擎InnoDB.MyISAM; mysql快速崛起的原因就是他是开源的; 性能一直是mysql自豪的一大特点; 2.mysql架构组成 麻雀虽小五脏俱全,mysql虽然简单但其内部结构并不简单; mysql物理文件组成之日志文件: 错误日志error log这里记录mysql运行时严重的警告和错误,以及mysql启动和关闭的日志信息 二进制日志 binary log 记录mysql运行时所有的query和query执

网络调优

关于网络调优,尤其是TCP Tuning(你可以以这两个关键词在网上找到很多文章),这里面有很多很多东西可以说.看看Linux下TCP/IP的那么多参数就知道了(顺便说一下,你也许不喜欢Linux,但是你不能否认Linux给我们了很多可以进行内核调优的权力).强烈建议大家看看<TCP/IP详解卷1:协议>这本书.我在这里只讲一些概念上的东西. A)TCP调优 我们知道TCP链接是有很多开销的,一个是会占用文件描述符,另一个是会开缓存,一般来说一个系统可以支持的TCP链接数是有限的,我们需要清楚

【Spark深入学习 -14】Spark应用经验与程序调优

----本节内容------- 1.遗留问题解答 2.Spark调优初体验 2.1 利用WebUI分析程序瓶颈 2.2 设置合适的资源 2.3 调整任务的并发度 2.4 修改存储格式 3.Spark调优经验 3.1 Spark原理及调优工具 3.2 运行环境优化 3.2.1 防止不必要的分发 3.2.2 提高数据本地性 3.2.3 存储格式选择 3.2.4 选择高配机器 3.3 优化操作符 3.3.1 过滤操作导致多小任务 3.3.2 降低单条记录开销 3.3.3 处理数据倾斜或者任务倾斜 3.

机器学习系列(11)_Python中Gradient Boosting Machine(GBM)调参方法详解

原文地址:Complete Guide to Parameter Tuning in Gradient Boosting (GBM) in Python by Aarshay Jain 原文翻译与校对:@酒酒Angie && 寒小阳([email protected]) 时间:2016年9月. 出处:http://blog.csdn.net/han_xiaoyang/article/details/52663170 声明:版权所有,转载请联系作者并注明出 1.前言 如果一直以来你只把GBM

iOS应用性能调优的25个建议和技巧

目录 我要给出的建议将分为三个不同的等级: 入门级. 中级和进阶级: 入门级(这是些你一定会经常用在你app开发中的建议) 1. 用ARC管理内存 2. 在正确的地方使用reuseIdentifier 3. 尽可能使Views透明 4. 避免庞大的XIB 5. 不要block主线程 6. 在Image Views中调整图片大小 7. 选择正确的Collection 8. 打开gzip压缩 中级(这些是你可能在一些相对复杂情况下可能用到的) 9. 重用和延迟加载Views 10. Cache, C

php调优

php.ini配置文件调优 1. expose_php off 2. register_globals off(重要,防止GET和POST变量自动注册为全局变量,一定要关闭) 3. 打开magic_quotes_gpc来防止SQL注入,重要!是防止SQL注入的重要手段,该参数将用户提交的SQL查询进行转换,如将'转换为\'. 4. display errors off 4. max_excution_time 30s 最长执行时间. 5. memory_limit,一个脚本能申请到的最大内存,防

mysql数据库调优

最近新到项目上,算是帮忙,遇见性能测试. 测试要求其实不高,现在是单mysql数据库,未分表,四千万数据,四百毫秒,上的压力是一千一百多tps,但是,动态的只占到了百分之二十左右,也就是两百左右的tps吧.服务器还是比较牛逼的,我看到了十几个cpu线程,估计超过一百G内存吧. 大体情况如上. 鄙人之前没优化过mysql,其实,是没调优过sql,只读过部分sql执行的原理,数据库的结构啥的,平常写sql和设计表的时候有些注意,实战调优经验为零,以前就算调了,没测试过,也白搭,这次算是逮到便宜了.