zoukankan      html  css  js  c++  java
  • CSPS模拟94

    我好菜啊。。。。。。

    %%%迪神AK

    虽然考试成绩不太好,但至少能想到正解了,也不会菜到打不出暴力。

    T1:想了半天不会,发现直接打高精可以拿到80分,就赶紧码完扔了,结果正解是利用double避免了高精运算

    解法:%%迪神,高精压位,同时只记录前300位进行比较。

    or利用double和除法,最后和1比较

    or正解:double,对所有数取log再进行比较

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #define LL double
     7 #define N 1000050
     8 using namespace std;
     9 int x,y;
    10 inline void work1()
    11 {
    12     LL a1=1,a2=0.0;
    13     a1=1.0*y*log(x);
    14     for(int i=1;i<=y;++i)a2+=1.0*log((double)i);
    15     if(a1>a2)puts("No");
    16     else puts("Yes");
    17 }
    18 int main()
    19 {
    20     freopen("yuuutsu.in","r",stdin);
    21     freopen("yuuutsu.out","w",stdout);
    22     int T;scanf("%d",&T);
    23     while(T--)
    24     {
    25         scanf("%d%d",&x,&y);
    26         work1();
    27     }
    28     fclose(stdin);fclose(stdout);
    29 }
    View Code

    T2:考场正解,细节打炸。将原数列差分掉,然后利用就可以将下标mod k进行操作了。

    注意特判:差分的区间为左闭右开。所以当右端点为n+1时是可以随意加的。然而当左端点为0时不能随便加,因为是左闭右开呀

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define LL long long
     6 #define N 2000050
     7 #define re register 
     8 using namespace std;
     9 LL s1[N];
    10 inline int read()
    11 {
    12     int s=0,b=0;char c=getchar();
    13     while(c>'9'||c<'0'){if(c=='-')b=1;c=getchar();}
    14     while(c>='0'&&c<='9')s=s*10+c-'0',c=getchar();
    15     if(b)return -s;
    16     return s;
    17 }
    18 int n,k,m;
    19 int a[N],al,pd[N];
    20 inline void add(int pos,int val)
    21 {
    22     pos%=k;
    23     if(pd[pos])return;
    24     if(s1[pos]==-val){s1[pos]=0;--al;return;}
    25     if(!s1[pos]){s1[pos]=val;++al;return;}
    26     s1[pos]+=val;
    27 }
    28 int main()
    29 {
    30     freopen("august.in","r",stdin);
    31     freopen("august.out","w",stdout);
    32     n=read(),k=read(),m=read();
    33     for(register int i=1;i<=n;++i)a[i]=read();
    34     for(register int i=n;i;--i)
    35         a[i]-=a[i-1],s1[i%k]+=a[i];
    36     pd[(n+1)%k]=1;
    37     for(int i=0;i<k;++i){
    38         if(pd[i])continue;
    39         if(s1[i])++al;
    40     }
    41     if(al)puts("No");
    42     else puts("Yes");
    43     for(int i=1,x,y;i<=m;++i)
    44     {
    45         x=read();y=read();
    46         if(y){add(x,y);add(x+1,-y);}
    47         if(al)puts("No");
    48         else puts("Yes");
    49     }
    50     fclose(stdin);fclose(stdout);
    51 }
    左端点为0不能加

    T3:这题好好写一下。

    考场上先打出了暴力,然后考虑加优化。

    暴力:

    1 for(int i=1,lca;i<=n;++i)
    2 {
    3     lca=a[i];ans+=c[lca];
    4     for(int j=i-1;j;--j){
    5         lca=LCA(lca,a[j]);
    6         ans+=c[lca];
    7     }
    8 }

    暴力枚举右端点,发现左端点在一段区间内时lca是一定的。

    那么这个东西可以用链表来维护。

    链表记录lca的值(id)和这个lca对应左端点的数量(ct)

    统计答案直接ct*id即可。

    然而这种打法还是会被一条链的数据卡掉

    深入挖掘它的性质。每插入一个新的右端点,会把链表内所有节点更新到新端点的祖先链上。(显然

    那么新加入的节点就一定会加到链表的队尾。且设当前加入的为a[j],那么a[j]和a[j-1]的lca之前的点是共用的。

    那么不断利用a[j]和a[j-1]的lca去弹掉链表的队尾。最后在队尾加入a[j]和a[j-1]的lca和a[j]即可

    考虑在每个节点再维护一个答案的前缀和(an)

    a[j]和a[j-1]的lca之前的所有的节点内所有东西(id,ct,an)都不变。

    那么直接更新a[j]和a[j-1]的lca和a[j]的答案即可。

    流程:

    新开节点,插入队尾,在队中删除不合法的节点并更新a[j]和a[j-1]的lca控制区间长度。

     1 #include<bits/stdc++.h>
     2 #define LL long long
     3 #define re register 
     4 #define N 200050
     5 using namespace std;
     6 inline int read()
     7 {
     8     int s=0,b=0;char c=getchar();
     9     while(c>'9'||c<'0'){if(c=='-')b=1;c=getchar();}
    10     while(c>='0'&&c<='9')s=s*10+c-'0',c=getchar();
    11     if(b)return -s;
    12     return s;
    13 }
    14 int n,m,a[N],c[N],kkk,num;
    15 struct node{int pre,ne,ct,id;LL an;}li[N*10];
    16 LL ans;
    17 int he[N],ne[N],to[N],fa[N],tot;
    18 inline void addedge(int x,int y){to[++tot]=y;ne[tot]=he[x];he[x]=tot;}
    19 int tp[N],dep[N],dfl[N],dfr[N],sz[N],hs[N],cnt;
    20 int po[N];
    21 inline void dfs1(int g)
    22 {
    23     dep[g]=dep[fa[g]]+1;sz[g]=1;
    24     for(int i=he[g];i;i=ne[i])
    25     {
    26         dfs1(to[i]);
    27         if(sz[to[i]]>sz[hs[g]])hs[g]=to[i];
    28         sz[g]+=sz[to[i]];
    29     }
    30 }
    31 inline void dfs2(int g)
    32 {
    33     dfl[g]=dfr[g]=++cnt;
    34     po[cnt]=g;
    35     if(hs[fa[g]]==g)tp[g]=tp[fa[g]];
    36     else tp[g]=g;
    37     if(hs[g])dfs2(hs[g]);
    38     for(int i=he[g];i;i=ne[i])
    39         if(to[i]!=hs[g])dfs2(to[i]);
    40     dfr[g]=cnt;
    41 }
    42 inline int LCA(int x,int y)
    43 {
    44     if(dep[x]>dep[y])swap(x,y);
    45     if(dfl[x]<=dfl[y]&&dfr[x]>=dfl[y])return x;
    46     while(tp[x]!=tp[y])
    47     {
    48         if(dep[tp[x]]>dep[tp[y]])swap(x,y);
    49         y=fa[tp[y]];
    50     }
    51     if(dep[x]>dep[y])return y;
    52     else return x;
    53 }
    54 inline void del(int x)
    55 {
    56     int a1=li[x].pre,a2=li[x].ne;
    57     if(a1)li[a1].ne=a2;
    58     if(a2)li[a2].pre=a1;
    59     if(!a2)kkk=a1;
    60 }
    61 int main()
    62 {
    63     freopen("sagittarius.in","r",stdin);freopen("sagittarius.out","w",stdout);
    64     n=read();
    65     for(int i=2;i<=n;++i){fa[i]=read();addedge(fa[i],i);}
    66     dfs1(1);dfs2(1);
    67     for(int i=1;i<=n;++i)a[i]=read();
    68     for(int i=1;i<=n;++i)c[i]=read();
    69     ans+=c[a[1]];li[++num].ct=1;
    70     li[num].id=a[1];kkk=num;
    71     li[num].an=c[a[1]];
    72     for(int j=2;j<=n;++j){
    73         li[++num].id=a[j];li[num].ct=1;
    74         li[kkk].ne=num;li[num].pre=kkk;
    75         kkk=num;int i,t;
    76         for(i=li[kkk].pre;i;i=li[i].pre){
    77             t=LCA(li[i].id,li[li[i].ne].id);
    78             if(t!=li[i].id){li[i].id=t;
    79                 if(li[i].id==li[li[i].ne].id){
    80                     li[i].ct+=li[li[i].ne].ct;
    81                     del(li[i].ne);
    82                 }
    83             }
    84             else {
    85                 if(li[i].id==li[li[i].ne].id){
    86                     li[i].ct+=li[li[i].ne].ct;
    87                     del(li[i].ne);
    88                 }
    89                 break;
    90             }
    91         }
    92         if(!i)i=1;
    93         for(;i;i=li[i].ne)li[i].an=li[li[i].pre].an+1ll*c[li[i].id]*li[i].ct;
    94         ans+=li[kkk].an;
    95     }
    96     cout<<ans<<endl;
    97 }
    代码和题解有些出入,但本质上是一样的

    复杂度证明:在每个点最多插入两个节点,每个节点被删除一次。复杂度为O(n)

    但由于还要求lca,复杂度变为O(nlogn)。(然而你用tarjan求lca做到O(n)我也没意见)

  • 相关阅读:
    [转]Visual Studio 2005中绝对定位控件的问题
    ado.net连sql2005的问题
    sql2005 清除日志
    【转帖】OnPreRender Render的区别
    sql2005锁,隔离级别等一些相关问题(一)
    获得远程文件MediaType
    jQuery学习教程 基础篇 归档
    PHP.ini Zend Debugger
    HTML5视频方案:支持iPad Safari、Firefox、Chrome、IE9876
    AS3 流媒体历史记录实现
  • 原文地址:https://www.cnblogs.com/loadingkkk/p/11767975.html
Copyright © 2011-2022 走看看