• 19.7.29 NOIP模拟10


    话说这次三道考试题直接可以连成一个段子:我一个辣鸡,连模板都不会打,只能跪倒在大佬面前;

    T1 辣鸡

    但是我实在是太辣鸡了,最后干的T1,时间不够用,连暴力都没打对,无奈之下交了一个qj程序,60分(rp分)

    正解?没有正解,正解就是一个大暴力,$ O(n^2) $直接出乎我的意料 ,这.......我真的是太辣鸡了;

    如此暴力的题,本人就懒得沾代码了;

    T2 模板

    一看题目名,我就知道这道题是最难的,没有办法,只能先留坑,因为我还没改过来呜呜呜 ~

    UPD:

    经过我的一上午的努力,终于70 了,虽然还没有AC但是我先来更一下缓解一下疲劳:

    T2首先我们可以想得到的就是一个大暴力,复杂度玄学,所以只有前面的30分;

    我是考试时候的代码,30(动用了我会的STL,发现STL真的很好片分)(大佬请自动忽略一下30分方法!)

    别人的30分思路都很正常,但是我的30分思路非常奇葩:

    首先,建树(恩,没什么特别的,然后开maxn个set和vector)先dfs一遍(我在后期调试时候发现的bug,需要dfs记录一下fa)

    然后,利用树上差分的思想,其实就是这个点到1节点,不不用lca,所以吗两上还是很好吗的;

    然后,记得给push进去的操作都打上时间戳,然后排序(是不是是非常的暴力?)

    把排完序的0(vector里是0)到min(题中要求的大小,vector.size())insert进set;

    这些操作都可以在另一个dfs中实现,所以整个暴力只需要dfs两遍,但是dfs内部的复杂度异常的大;

    最后统计答案的时候就输出set.size();

    本来dfs里带上dfs的复杂度就不好算,而且带上了STL,反正我是算不出来我打的暴力的复杂度,所以我也不证明复杂度了。

    30分代码:

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #include<cmath>
      5 #include<cstdlib>
      6 #include<set>
      7 #include<algorithm>
      8 #include<vector>
      9 using namespace std;
     10 #define debug(x) cout<<x<<" debug!"<<endl;
     11 #define LL long long
     12 #define re register
     13 const int L=1<<20|1;
     14 char buffer[L],*S,*T;
     15 #define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++)
     16 inline int read(){
     17     re int a=1,b=0;char t;
     18     do{t=getchar();if(t=='-')a=-1;}while(t>'9'||t<'0');
     19     do{b=b*10-'0'+t;t=getchar();}while(t>='0'&&t<='9');
     20     return a*b;
     21 }
     22 const int maxn=1e6;
     23 int n,m,tt,q;
     24 int head[maxn],ver[maxn],nxt[maxn],tot;
     25 inline void add(re int x,re int y){ver[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
     26 int vanum[maxn];
     27 bool vc[maxn],vvc[maxn];
     28 int fa[maxn];
     29 struct G{
     30 int c,t;
     31 };
     32 vector<G>d[maxn];
     33 set<int>w[maxn];
     34 bool v[maxn];
     35 int qe=0;
     36 bool cmp(G a,G b){return a.t<b.t;}
     37 void dfsz(re int x)
     38 {
     39     vc[x]=1;
     40     for(re int i=head[x];i;i=nxt[i])
     41     {
     42         re int y=ver[i];
     43         if(vc[y])continue;
     44         fa[y]=x;
     45         dfsz(y);
     46     }
     47 }
     48 void dfs(re int x)
     49 {
     50     v[x]=1;
     51     for(re int i=head[x];i;i=nxt[i])
     52     {
     53         re int y=ver[i];
     54         if(v[y]||y==fa[x])continue;
     55         dfs(y);
     56         for(re int j=0;j<d[y].size();j++)
     57             d[x].push_back(d[y][j]);
     58         sort(d[y].begin(),d[y].end(),cmp);
     59         for(re int k=0;k<min(vanum[y],(int)d[y].size());k++)
     60             w[y].insert(d[y][k].c);
     61     }
     62 }
     63 void dfs2(int x)
     64 {
     65     vvc[x]=1;
     66     for(int i=head[x];i;i=nxt[i])
     67     {
     68         int y=ver[i];
     69         if(vvc[y]||y==fa[x])continue;
     70         dfs2(y);
     71         for(set<int>::iterator it =w[y].begin();it!=w[y].end();it++)
     72             w[x].insert(*it);
     73     }
     74 }
     75 void qjj()
     76 {
     77     re int ca,col;
     78     m=read();
     79     for(re int i=1;i<=m;i++)
     80     {
     81         ca=read(),col=read();
     82         w[ca].insert(col);
     83     }
     84     dfs2(1);
     85     q=read();
     86     re int xi=0;
     87     for(re int i=1;i<=q;i++)
     88     {    
     89         xi=read();
     90         printf("%d
    ",w[xi].size());
     91     }
     92 }
     93 int main()
     94 {
     95     //freopen("T2.txt","r",stdin);
     96     n=read();
     97     int u,v;
     98     for(re int i=1;i<=n-1;i++)
     99     {
    100         u=read(),v=read();
    101         add(u,v),add(v,u);
    102     }
    103     dfsz(1);
    104     for(re int i=1;i<=n;i++)
    105     vanum[i]=read();
    106     m=read();
    107     re int ca,col;
    108     for(re int i=1;i<=m;i++)
    109     {
    110         ca=read(),col=read();
    111         G ooo;
    112         ooo=(G){col,++tt};
    113         d[ca].push_back(ooo);
    114     }
    115     q=read();
    116     re int xi=0;
    117     dfs(1);
    118     sort(d[1].begin(),d[1].end(),cmp);
    119     for(re int k=0;k<min(vanum[1],(int)d[1].size());k++)
    120         w[1].insert(d[1][k].c);
    121     for(re int i=1;i<=q;i++)
    122     {    
    123         xi=read();
    124         printf("%d
    ",w[xi].size());
    125     }
    126 }
    30

    然后,我就开始了漫漫优化路,整个我先是把我的STL想办法替换掉,当然我的set是去不掉的(我有不会打红黑树)所以我还是T

    但是,我忽然发现,我考试的时候没有看数据范围(我真晕!)所以我没有看见k==1e5的情况;

    其实按照我的qj技术,把这些点qj掉是可以的,所以,我就挂着我上面的暴力把程序交到70分,然后看了,某丁的线段树合并,才知道我里整洁其实很远,(其实是沉迷STL函数无法自拔),然后找丁丁学习了一下,总算是打出了类似正解的程序,(其实也是qj),特别感谢moudinggg,所以,不要沉迷与自己的错解,有时这样会使你离正解越来越远;

    具体的就是线段树合并,类似与之前的 雨天的尾巴 那道题,但是仔细一看就知道有很大的不同,其实就是线段树合并的思想;

    70分代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<vector>
      6 #include<set>
      7 #include<cmath>
      8 using namespace std;
      9 #define re register
     10 #define LL long long
     11 const LL maxn=(int)(4e5+10)*4;
     12 inline LL read()
     13 {
     14     re LL a=1,b=0;char t;
     15     do{t=getchar();if(t=='-')a=-1;}while(t>'9'||t<'0');
     16     do{b=b*10-'0'+t;t=getchar();}while(t>='0'&&t<='9');
     17     return a*b;
     18 }
     19 set<LL>st[maxn];
     20 LL head[maxn],ver[maxn],vvt[maxn],nxt[maxn];
     21 LL n,m,q,tot,tm[maxn],vanum[maxn],col[maxn],d[maxn],ans[maxn];
     22 vector<LL>tw[1010];
     23 LL col1[1010][1010],fa[maxn],colll[maxn],pos[maxn],b[maxn];
     24 LL rt[maxn],sum[maxn],L[maxn],R[maxn],ls[maxn],rs[maxn],W[maxn],cnt;
     25 inline void add(LL x,LL y){vvt[++tot]=x;ver[tot]=y;nxt[tot]=head[x];head[x]=tot;}
     26 bool v1[maxn],v2[maxn];
     27 void dfs1(LL x)
     28 {    
     29     v1[x]=1;
     30     for(LL i=head[x];i;i=nxt[i])
     31     {
     32         LL y=ver[i];
     33         if(v1[y])continue;
     34         fa[y]=x;
     35         dfs1(y);
     36     }
     37 }
     38 void build(LL &rt,LL l,LL r,LL w)
     39 {
     40     if(!rt) 
     41     {
     42         rt=++cnt;
     43         L[rt]=l;
     44         R[rt]=r;
     45     }
     46     LL mid=l+r>>1;
     47     if(l==r) 
     48     {
     49         if(sum[rt]==1)return ;
     50         else
     51         {    
     52             sum[rt]=1;
     53             W[rt]=w;
     54             return ;
     55         }
     56     }
     57     if(w<=mid) build(ls[rt],l,mid,w);
     58     else build(rs[rt],mid+1,r,w);
     59     sum[rt]=sum[ls[rt]]+sum[rs[rt]];
     60 }
     61 LL merge(LL x,LL y)
     62 {
     63     if(!x||!y)return x+y;
     64     if(L[x]==R[x]&&L[x]==L[y]&&R[x]==R[y])return x;
     65     ls[x]=merge(ls[x],ls[y]);
     66     rs[x]=merge(rs[x],rs[y]);
     67     sum[x]=sum[ls[x]]+sum[rs[x]];
     68     return x;
     69 }
     70 void dfs2(LL x)
     71 {
     72     v2[x]=1;
     73     for(LL i=head[x];i;i=nxt[i])
     74     {    
     75         LL y=ver[i];
     76         if(v2[y])continue;
     77         dfs2(y);
     78         rt[x]=merge(rt[x],rt[y]);
     79     }
     80     ans[x]=sum[rt[x]];
     81 }
     82 int main()
     83 {
     84     //freopen("simple2.txt","r",stdin);
     85     n=read();
     86     for(LL i=1,x,y;i<n;i++)
     87         x=read(),y=read(),add(x,y),add(y,x);
     88     for(LL i=1;i<=n;i++) scanf("%lld",&vanum[i]);
     89     m=read();
     90     dfs1(1);
     91     for(LL i=1,x,y;i<=m;i++) pos[i]=read(),colll[i]=read(),b[i]=colll[i];
     92     sort(b+1,b+1+m);
     93     LL sz=unique(b+1,b+m+1)-b-1;
     94     for(LL i=1;i<=m;i++) colll[i]=lower_bound(b+1,b+sz+1,colll[i])-b;
     95     if(n<=1e3&&m<=1e3)
     96     {
     97         for(LL i=1;i<=m;i++)
     98         {
     99             LL x=pos[i],y=colll[i];
    100             while(x)
    101             {
    102                 if(!col1[x][y]&&ans[x]<vanum[x]) ans[x]++;
    103                 else if(vanum[x]>ans[x]) vanum[x]--;
    104                 col1[x][y]=1;
    105                 x=fa[x];
    106             }
    107         }
    108         q=read();
    109         for(LL i=1,x;i<=q;i++)
    110         {    
    111             x=read();
    112             printf("%lld
    ",ans[x]);
    113         }
    114         return 0;
    115     }
    116     for(LL i=1,x,y;i<=m;i++) 
    117         build(rt[pos[i]],1,sz,colll[i]);
    118     dfs2(1);
    119     q=read();
    120     for(LL i=1,x;i<=q;i++)
    121     {    
    122         x=read();
    123         printf("%lld
    ",ans[x]);
    124     }
    125 }
    70

    30号上午就先更到这,我的坑还没填完,等我改AC在更!

    UPD:我终于把这道题该过去了,说实话,这道题是非常的坑*;

    就我之前提到的70分代码,能不能改到100呢?反正我是没有改到,然后只是利用了70分代码里线段树合并的思想,(但是这里是启发式合并),关于启发式合并,我记得sk学长好像在之前讲树套树的时候讲到过,当时一脸蒙蔽,完全不知道在干啥,现在终于知道了,其实就是暴力的把小的那颗线段树里的节点往另一棵里插,注意一定是小的往大的里插,这样才能有卓越的复杂度,然后,利用树链剖分的思想,其实就是利用了树链剖分里重儿子的概念,然后在合并(启发是合并,这里及后文简称合并)过程中只保留重儿子,而且轻儿子清空,这样就保证不会TLE,有些dalao一只TLE30左右,应该就是清掉了重儿子。总而言之,这道题很毒瘤,也然我看到了自己有很多的不足,我其实还是T2颓了代码,不然我是真的想不到正解,包括就像网上那个说的,要是NOIP六道题都是这个难度的,我还是滚回去文化课吧。(尽力不滚回去!)

    我就把我颓的std放上来吧,我写了注释,不过应该是对的,不对的话就在评论区告诉我吧!

      1 //注释解释2019.7.29 T2模板 
      2 //仅是本人自我理解;
      3 //copyright by zzyy;
      4 //注释创建者:lsc
      5 //powered by lsc;
      6 //----------------------*
      7 #include<cstdio>
      8 #include<cstring>
      9 #include<cstdlib>
     10 #include<algorithm>
     11 #include<map>
     12 #include<vector>
     13 #define maxn 401000
     14 using namespace std;
     15 int m,n,k,tot,first[maxn],w[maxn],ans[maxn],q,siz[maxn],color,son[maxn],t[maxn];
     16 int data[maxn*4],tsiz[maxn*4],lazy[maxn*4];
     17 vector<int>bel[maxn],dr[maxn];
     18 map<int,int>judge;
     19 struct node{int to,next;}a[maxn*2];
     20 inline void add(int x,int y){a[++tot]=(node){y,first[x]};first[x]=tot;}
     21 inline void pushdown(int x)//懒标记下放
     22 {
     23     if(lazy[x]==0) return;
     24     lazy[x<<1]=lazy[x<<1|1]=1;
     25     lazy[x]=data[x<<1]=data[x<<1|1]=tsiz[x<<1]=tsiz[x<<1|1]=0;
     26 }
     27 inline void pushup(int x)//信息上传
     28 {
     29     data[x]=data[x<<1]+data[x<<1|1];
     30     tsiz[x]=tsiz[x<<1]+tsiz[x<<1|1];
     31 }
     32 inline void update(int x,int l,int r,int val,int derta,int sum)//权值线段树的更新答案操作
     33 {
     34     data[x]+=derta,tsiz[x]+=sum;
     35     if(l==r) return ;
     36     int mid=(l+r)>>1;
     37     pushdown(x);
     38     if(val<=mid) update(x<<1,l,mid,val,derta,sum);
     39     else         update(x<<1|1,mid+1,r,val,derta,sum);
     40     pushup(x);
     41 }
     42 inline int query(int x,int l,int r,int sum)//单点查询键值小于sum的值的个数;
     43 {
     44     if(sum<=0) return 0;
     45     if(l==r)   return data[x];
     46     int mid=(l+r)>>1;
     47     pushdown(x);
     48     if(tsiz[x<<1]<=sum)
     49         return data[x<<1]+query(x<<1|1,mid+1,r,sum-tsiz[x<<1]);
     50     else
     51         return query(x<<1,l,mid,sum);
     52 }
     53 inline void init_tim(int x)//打标记
     54 {
     55     data[1]=siz[1]=0, lazy[1]=1;
     56     for(register int i=0;i<bel[x].size();++i) t[bel[x][i]]=0;//t是一个桶,保存键值的个数
     57 }
     58 inline void init_tree(int x)        //把x节点的操作插入到权值线段树中
     59 {
     60     for(register int i=0;i<bel[x].size();++i)
     61     {
     62         int col=bel[x][i], tim=dr[x][i];
     63         if(!t[col]) update(1,1,m,tim,1,0),t[col]=tim;
     64         else if(t[col]>tim)
     65         {
     66             update(1,1,m,t[col],-1,0);
     67             update(1,1,m,tim,1,0);
     68             t[col]=tim;
     69         }
     70         update(1,1,m,tim,0,1);
     71     }
     72 }
     73 inline void insert(int x,int y)            //将y插入到x中,就是启发式合并
     74 {
     75     for(register int i=0;i<bel[y].size();++i)
     76         bel[x].push_back(bel[y][i]),dr[x].push_back(dr[y][i]);
     77     bel[y].clear(), dr[y].clear();
     78 }
     79 
     80 inline void dfs_pre(int x,int dad)        //树链剖分
     81 {    
     82     siz[x]=bel[x].size();
     83     for(register int i=first[x];i;i=a[i].next)
     84     {    
     85         int to=a[i].to;
     86         if(to==dad) continue;
     87         dfs_pre(to,x); siz[x]+=siz[to];
     88         if(siz[son[x]]<siz[to]) son[x]=to;
     89     }
     90 }
     91 inline void dfs(int x,int dad)
     92 {
     93     for(register int i=first[x];i;i=a[i].next)
     94     {    
     95         int to=a[i].to;
     96         if(son[x]==to||to==dad) continue;
     97         dfs(to,x); 
     98         init_tim(to);
     99     }
    100     if(son[x]) dfs(son[x],x);
    101         init_tree(x);
    102     for(register int i=first[x];i;i=a[i].next)
    103     {
    104         int to=a[i].to;
    105         if(to==dad||to==son[x]) continue;
    106         init_tree(to);
    107     }
    108     ans[x]=query(1,1,m,w[x]);
    109     if(son[x])
    110     {
    111         insert(son[x],x);
    112         swap(bel[son[x]],bel[x]); swap(dr[son[x]],dr[x]);
    113         for(register int i=first[x];i;i=a[i].next)
    114         {
    115             int to=a[i].to;
    116             if(to==dad) continue;
    117             insert(x,to);
    118         }
    119     }
    120 }
    121 int main()
    122 {
    123     freopen("simple1.txt","r",stdin);
    124     scanf("%d",&n);
    125     for(register int i=1,x,y;i<n;++i) 
    126         scanf("%d%d",&x,&y), add(x,y),add(y,x);        //树建边
    127     for(register int i=1;i<=n;++i)    
    128         scanf("%d",&w[i]);                //限制条件
    129     scanf("%d",&m);
    130     for(register int i=1,x,y;i<=m;++i)
    131     {
    132         scanf("%d%d",&x,&y);
    133         if(!judge[y]) judge[y]=++color;        //将颜色种类离散化
    134         y=judge[y];//现在的y是离散化之后的y;
    135         bel[x].push_back(y), dr[x].push_back(i);//bel存的是颜色,dr存的是时间戳;
    136     }
    137     siz[0]=-1;  
    138     dfs_pre(1,0);  
    139     dfs(1,0);
    140     scanf("%d",&q);
    141     for(register int i=1,x;i<=q;++i) 
    142         scanf("%d",&x), printf("%d
    ",ans[x]);
    143 }
    100

    T3 大佬

    其实这道题考场上思路就接近正解,就发现一些考试的时候我会出现思路的瓶颈,然后其实再想一点点就可以出正解,然后,这道题就炸了,

    T3题解里给了一堆扯*玩意,所以我不按题解说:

    总的方案数就是$ m^k $然后这个数做分子(记得逆元)然后枚举最大的点数(劳累值)进行运算,(这部就是我的考试思路啊!)对于每一个

    最大的劳累值,我们知道这可能的方案数是 $ i^k $然而其中存在不合法的方案数,即$ (i-1)^k $(可以想一想,这很好想)然后

    $ (i^k-(i-1)^k)/(m^k) $就是最大劳累值是i的时候的概率,乘以w的映射值就是期望,这n-k+1天的情况都是一样的(由于难度是随机的,所以这些天都是一样的)那么$ ans=sum((i^k-(i-1)^k)/(m^k)*w[i])*(n-k+1) $

    然后这道题有一个测试点是k>n的情况,然后特判一下,你就愉快的收获了100分的好成绩(逃)

    T1 T3比较简单,不沾代码!

    这次考试我也是见证了rp的作用,就是qj都能拿到高分,其实我的qj第一次交的时候只有20分,当时我就只qj了第一个测试点和第二个测试点,后来我就想,反正也是qj就直接else一下printf一下累计和ans,本着反正能骗到就骗,骗不到拉到的心态加了一个else,然后出乎意料的是T1分数仅次于正解,但是仔细看解法和正解半毛钱关系没有,所以这次可能是rp在发挥作用,然后我也仔细想了一下,这次只是运气好,但是我并不能保证自己NOIP的时候运气好,难道没有技术,光指望qj就能拿省一?就能进省队?不存在的!所以还是要努力的提升自己的技术,用实力去换来幸运,这可能就是我从这次考试获得的启示吧!

  • 相关阅读:
    array_values — 返回数组中所有的值
    array_unshift — 在数组开头插入一个或多个单元
    array_unique — 移除数组中重复的值
    array_uintersect — 计算数组的交集,用回调函数比较数据
    array_uintersect_uassoc — 带索引检查计算数组的交集,用单独的回调函数比较数据和索引
    职场中的起跑线上,从赢在一个办公邮箱开始
    可终身使用的会员邮箱靓号,到底有多酷?
    商务业务人员,用什么邮箱更能获得认可?
    电子邮箱有哪些类型,2020什么邮箱最火爆?
    外贸邮箱用哪个比较好?企业域名邮箱注册哪个好?
  • 原文地址:https://www.cnblogs.com/hzoi-lsc/p/11267551.html
Copyright © 2020-2023  润新知