zoukankan      html  css  js  c++  java
  • 【NOIP 2016 总结】

    距离杯赛已经很久了,然而我现在才打总结。。

    我好惨的说..两场才380。。。


    DAY 1

    第一题 toy

    送分题,模拟的时候+一下再mod一下就好。

    [当时打完这题就没再看一眼了,好方的说]

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define Maxn 100010
    
    int a[Maxn];
    char s[Maxn][20];
    
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            scanf("%s",s[i]);
        }
        int now=0;
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            y%=n;
            if(a[now]==1&&x==0) now=(now+y)%n;
            else if(a[now]==1) now=(now+n-y)%n;
            else if(x==0) now=(now+n-y)%n;
            else now=(now+y)%n;
        }
        printf("%s
    ",s[now]);
        return 0;
    }
    View Code

    第二题 running

    感觉这题是全场最难的【是吧??

    但其实【啊好像也不是很难。。

    怎么比赛的时候就脑子那么乱呢

    我的方法是,把路径分成两段,然后lca的特殊算。

    假如lca在st上面,假设这条路径对z有贡献(z在lca和st之间),那么dep[z]-dep[st]=w[z]   =>  dep[z]-w[z]=dep[st]

    那么对于z来说,就是求经过自己的路径中dep等于dep[z]-w[z]的有多少个。

    对于路径,我们在st上打一个加入标记,在lca上打一个删除标记,那么对于z,就是求其子树和(每个点用dfs序做,问题变成求区间和,单点修改,区间询问,可以用树状数组维护)。

    对于加入和删除,我们按照st的dep排序,对于每个点,我们按照dep[z]-dep[st]排序,值相等是一起做,这时O(n+m)的。

    对于右半边的路径类似,有2*dep[lca]-dep[st]=dep[z]+w[z]。

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define Maxn 300010
    #define Maxm 300010
    
    struct node
    {
        int x,y,next,c;
    }t[Maxn*2];int len=0;
    int n,m;
    
    struct hp
    {
        int x,y,c;
    }q[Maxm],qq[Maxm],nq[Maxn];
    int l1,l2;
    
    int first[Maxn];
    
    void ins(int x,int y)
    {
        t[++len].x=x;t[len].y=y;
        t[len].next=first[x];first[x]=len;
    }
    
    bool cmp(hp x,hp y) {return x.c<y.c;}
    
    int son[Maxn],dep[Maxn],sm[Maxn];
    int fa[Maxn];
    void dfs(int x,int f)
    {
        sm[x]=1;dep[x]=dep[f]+1;
        fa[x]=f;
        son[x]=0;
        for(int i=first[x];i;i=t[i].next) if(t[i].y!=f)
        {
            int y=t[i].y;
            dfs(y,x);
            sm[x]+=sm[y];
            if(sm[y]>sm[son[x]]) son[x]=y;
        }
    }
    
    int tp[Maxn],dfn[Maxn],rt[Maxn],cnt=0;
    void dfs2(int x,int tpp)
    {
        tp[x]=tpp;rt[x]=dfn[x]=++cnt;
        if(son[x]) dfs2(son[x],tpp),rt[x]=rt[son[x]];
        for(int i=first[x];i;i=t[i].next) if(t[i].y!=fa[x]&&t[i].y!=son[x])
        {
            int y=t[i].y;
            dfs2(y,y);
            rt[x]=rt[y];
        }
    }
    
    int lca(int x,int y)
    {
        int tt;
        while(tp[x]!=tp[y])
        {
            if(dep[tp[x]]<dep[tp[y]]) tt=x,x=y,y=tt;
            x=fa[tp[x]];
        }
        if(dep[x]<dep[y]) return x;
        return y;
    }
    
    int w[Maxn],ans[Maxn],c[Maxn];
    
    void add(int x,int y)
    {
        for(int i=x;i<=n;i+=i&(-i))
            c[i]+=y;
    }
    
    int query(int l,int r)
    {
        int ans=0;
        for(int i=r;i>=1;i-=i&(-i))
            ans+=c[i];
        l--;
        for(int i=l;i>=1;i-=i&(-i))
            ans-=c[i];
        return ans;
    }
    
    void ffind()
    {
        int l,r;
        l=2,r=1;
        memset(c,0,sizeof(c));
        for(int i=1;i<=n;i++)
        {
            int x=nq[i].x;
            if(i==1||nq[i].c!=nq[i-1].c)
            {
                for(int j=l;j<r;j++)
                {
                    add(q[j].x,-1),add(q[j].y,1);
                }
                l=r;
                while(q[l].c<nq[i].c&&l<=l1) l++;
                r=l;
            }
                while(q[r].c==nq[i].c&&r<=l1)
                {
                    add(q[r].x,1);add(q[r].y,-1);
                    //printf("add %d
    ",r);
                    r++;
                }
            ans[x]+=query(dfn[x],rt[x]);
        }
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            ins(x,y);ins(y,x);
        }
        for(int i=1;i<=n;i++) scanf("%d",&w[i]);
        dfs(1,0);
        dfs2(1,1);
        l1=l2=0;
        memset(ans,0,sizeof(ans));
        for(int i=1;i<=m;i++)
        {
            int x,y,z;
            scanf("%d%d",&x,&y);
            z=lca(x,y);
            q[++l1].x=dfn[x];q[l1].y=dfn[z];q[l1].c=dep[x];
            qq[++l2].x=dfn[y];qq[l2].y=dfn[z];qq[l2].c=2*dep[z]-dep[x];
            
            if(w[z]==dep[x]-dep[z]) ans[z]++;
        }
        sort(q+1,q+1+l1,cmp);
        for(int i=1;i<=n;i++) nq[i].x=i,nq[i].c=dep[i]+w[i];
        sort(nq+1,nq+1+n,cmp);
        ffind();
        
        for(int i=1;i<=l2;i++) q[i]=qq[i];
        l1=l2;
        sort(q+1,q+1+l1,cmp);
        for(int i=1;i<=n;i++) nq[i].x=i,nq[i].c=dep[i]-w[i];
        sort(nq+1,nq+1+n,cmp);
        ffind();
        
        for(int i=1;i<=n;i++) printf("%d ",ans[i]);
        printf("
    ");
        return 0;
    }
    View Code

    第三题 classroom

    其实是一个很明显的期望DP。【当时脑抽again = = toxic

    状态f[i][j][0]表示前i段,用j次机会,最后一次不使用机会的期望值。

    状态f[i][j][1]表示前i段,用j次机会,最后一次使用机会的期望值。

    f[i][j][0]=min(f[i-1][j][0]+1.0*dis[c[i-1]][c[i]])

    f[i][j][0]=min(f[i-1][j][1]+1.0*dis[d[i-1]][c[i]]*k[i-1]+(1-k[i-1])*dis[c[i-1]][c[i]]);

    f[i][j][1]=min(f[i-1][j-1][0]+k[i]*(dis[c[i-1]][d[i]])+(1-k[i])*(dis[c[i-1]][c[i]]));

    f[i][j][1]=min(f[i-1][j-1][1]+ k[i]*(dis[d[i-1]][d[i]]*k[i-1]+dis[c[i-1]][d[i]]*(1-k[i-1]))+ (1-k[i])*(dis[d[i-1]][c[i]]*k[i-1]+dis[c[i-1]][c[i]]*(1-k[i-1])));

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<queue>
     6 #include<algorithm>
     7 using namespace std;
     8 #define Maxn 2010
     9 #define INF 0xfffffff
    10 
    11 int c[Maxn],d[Maxn];
    12 double f[Maxn][Maxn][2],k[Maxn];
    13 
    14 int n,m,v,e;
    15 
    16 int mmin(int x,int y) {return x<y?x:y;}
    17 double mymin(double x,double y) {return x<y?x:y;}
    18 
    19 int dis[Maxn][Maxn];
    20 
    21 void floyd()
    22 {
    23     for(int l=1;l<=v;l++)
    24       for(int i=1;i<=v;i++)
    25         for(int j=1;j<=v;j++)
    26           dis[i][j]=mmin(dis[i][j],dis[i][l]+dis[l][j]);
    27 }
    28 
    29 int main()
    30 {
    31     scanf("%d%d%d%d",&n,&m,&v,&e);
    32     for(int i=1;i<=n;i++) scanf("%d",&c[i]);
    33     for(int i=1;i<=n;i++) scanf("%d",&d[i]);
    34     for(int i=1;i<=n;i++) scanf("%lf",&k[i]);
    35     memset(dis,63,sizeof(dis));
    36     for(int i=1;i<=e;i++)
    37     {
    38         int x,y,c;
    39         scanf("%d%d%d",&x,&y,&c);
    40         dis[x][y]=mmin(dis[x][y],c);
    41         dis[y][x]=mmin(dis[y][x],c);
    42     }
    43     for(int i=1;i<=v;i++) dis[i][i]=0;
    44     floyd();
    45     
    46     for(int i=1;i<=n;i++)
    47      for(int j=0;j<=n;j++)
    48      f[i][j][0]=f[i][j][1]=INF;
    49      double ans=INF;
    50      f[1][0][0]=f[1][1][1]=0;f[1][1][0]=0;
    51     for(int i=2;i<=n;i++)
    52      for(int j=0;j<=i&&j<=m;j++)
    53      {
    54         //printf("%.2lf
    ",ans);
    55         //bu yong
    56          f[i][j][0]=mymin(f[i][j][0],f[i-1][j][0]+1.0*dis[c[i-1]][c[i]]);
    57         f[i][j][0]=mymin(f[i][j][0],f[i-1][j][1]+1.0*dis[d[i-1]][c[i]]*k[i-1]+(1-k[i-1])*dis[c[i-1]][c[i]]);
    58          
    59          //yong
    60         if(j>0)
    61         {
    62             f[i][j][1]=mymin(f[i][j][1],f[i-1][j-1][0]+k[i]*(dis[c[i-1]][d[i]])+(1-k[i])*(dis[c[i-1]][c[i]]));
    63             f[i][j][1]=mymin(f[i][j][1],f[i-1][j-1][1]+
    64             k[i]*(dis[d[i-1]][d[i]]*k[i-1]+dis[c[i-1]][d[i]]*(1-k[i-1]))+
    65             (1-k[i])*(dis[d[i-1]][c[i]]*k[i-1]+dis[c[i-1]][c[i]]*(1-k[i-1])));
    66         }
    67      }
    68     for(int i=0;i<=m&&i<=n;i++) ans=mymin(ans,f[n][i][0]),
    69     ans=mymin(ans,f[n][i][1]);
    70     printf("%.2lf
    ",ans);
    71     return 0;
    72 }
    View Code

    第一天 100+25+55 哭泣

    第二题交了纯暴力,第三题错误DP。。


    DAY 2

    第一题 problem

    用杨辉三角搞一搞就好了。

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<iostream>
     6 using namespace std;
     7 #define Maxn 2010
     8 
     9 int p[Maxn],f[Maxn][Maxn];
    10 int k;
    11 
    12 
    13 int c[Maxn][Maxn],ans[Maxn][Maxn];
    14 
    15 void init()
    16 {
    17     for(int i=0;i<=2000;i++) c[i][0]=1;
    18     for(int i=1;i<=2000;i++)
    19      for(int j=1;j<=i;j++)
    20       c[i][j]=(c[i-1][j-1]+c[i-1][j])%k;
    21     
    22     memset(f,0,sizeof(f));
    23     for(int i=1;i<=2000;i++)
    24     {
    25         f[i][0]=0;
    26       for(int j=1;j<=i;j++)
    27       {
    28            f[i][j]=f[i][j-1];
    29            if(c[i][j]==0) f[i][j]++;
    30       }
    31       for(int j=i+1;j<=2000;j++) f[i][j]=f[i][j-1];
    32     }
    33     for(int i=1;i<=2000;i++) ans[1][i]=f[1][i];
    34     for(int i=2;i<=2000;i++)
    35      for(int j=1;j<=2000;j++) ans[i][j]=ans[i-1][j]+f[i][j];
    36 }
    37 
    38 int main()
    39 {
    40     int T;
    41     scanf("%d%d",&T,&k);
    42     init();
    43     while(T--)
    44     {
    45         int n,m;
    46         scanf("%d%d",&n,&m);
    47         printf("%d
    ",ans[n][m]);
    48     }
    49     return 0;    
    50 }
    View Code

    第二题 earthworm

    在暴力的基础上看出来有单调性就可以AC了。

    切出来的左边递减,右边也递减,每次取三部分的最大值出来切,注意不要想成全部+q,用一个累加器,然后切出来的那部分-q是一样的。

    //代码很丑,因为在洛谷上调TLE,,洛谷好慢的说。。

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<iostream>
     6 using namespace std;
     7 #define Maxn 100010
     8 #define Maxm 7000010
     9 #define INF 0xfffffff
    10 #define LL long long
    11 
    12 int a[Maxn];
    13 
    14 LL add=0;
    15 LL v1[Maxm],v2[Maxm];
    16 
    17 int n,m,q,u,v,t;
    18 int l1,l2;
    19 
    20 bool cmp(int x,int y) {return x>y;}
    21 
    22 
    23 int main()
    24 {
    25     scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t);
    26     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    27     sort(a+1,a+1+n,cmp);
    28     l1=1,l2=1;
    29     v1[0]=v2[0]=0;
    30     a[0]=1;
    31     for(LL i=1;i<=m;i++)
    32     {
    33         
    34         
    35     LL now=-INF;
    36     now*=10000000;
    37     if(a[0]<=n) now=now>a[a[0]]?now:a[a[0]];
    38     if(l1<=v1[0]) now=now>v1[l1]?now:v1[l1];
    39     if(l2<=v2[0]) now=now>v2[l2]?now:v2[l2];
    40     if(a[0]<=n&&now==a[a[0]]) a[0]++;
    41     else if(l1<=v1[0]&&now==v1[l1]) l1++;
    42     else if(l2<=v2[0]&&now==v2[l2]) l2++; 
    43         now+=add;
    44         
    45         
    46         
    47         
    48         
    49         
    50         if(i%t==0) printf("%lld ",now);
    51         add+=q;
    52         LL x=now*u/v,y=now-x;
    53         v1[++v1[0]]=x-add;v2[++v2[0]]=y-add;
    54     }
    55     printf("
    ");
    56     for(int i=1;i<=n+m;i++)
    57     {
    58         
    59         
    60         
    61     LL now=-INF;
    62     now*=10000000;
    63     if(a[0]<=n) now=now>a[a[0]]?now:a[a[0]];
    64     if(l1<=v1[0]) now=now>v1[l1]?now:v1[l1];
    65     if(l2<=v2[0]) now=now>v2[l2]?now:v2[l2];
    66     if(a[0]<=n&&now==a[a[0]]) a[0]++;
    67     else if(l1<=v1[0]&&now==v1[l1]) l1++;
    68     else if(l2<=v2[0]&&now==v2[l2]) l2++; 
    69     now+=add;
    70         
    71         if(i%t==0) printf("%lld ",now);
    72     }
    73     printf("
    ");
    74     return 0;    
    75 }
    View Code

    第三题 angrybirds

    其实就是状压dp啊

    注意精度,不要*100然后强转int【我就死在强转int,不然用round也可以

    还有一个小地方就是,你可能会枚举两个点,是18^2的,但是其实你可以只枚举一个点,规定这一次一定先把某头猪弄下来(因为你后面总有一次要把这头猪弄下来的,不如现在先做了,反正没什么区别),这样就是一个18,这样就可以过了。

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<iostream>
     6 using namespace std;
     7 #define Maxd 300010
     8 #define INF 0xfffffff
     9 
    10 double xx[20],yy[20];
    11 
    12 int f[Maxd];
    13 int n,m;
    14 
    15 int gcd(int a,int b)
    16 {
    17     if(b==0) return a;
    18     return gcd(b,a%b);
    19 }
    20 
    21 double fabs(double x) {return x<0?-x:x;}
    22 
    23 int sum;
    24 int get_s(int a,int b,int s)
    25 {
    26     int ss=s;
    27     double A,B;
    28     A=(xx[b]*yy[a]-xx[a]*yy[b])*1.0/(xx[b]*xx[a]*xx[a]-xx[a]*xx[b]*xx[b]);
    29     B=(yy[a]-A*xx[a]*xx[a])*1.0/xx[a];
    30     if(A>=0)
    31     {
    32         return -1;
    33     }
    34     sum=0;
    35     for(int i=1;i<=n;i++) if((1<<i-1)&s)
    36     {
    37         if(fabs(A*xx[i]*xx[i]+B*xx[i]-yy[i])<0.000001) ss^=(1<<i-1),sum++;
    38     }
    39     return ss;
    40 }
    41 
    42 int mymin(int x,int y) {return x<y?x:y;}
    43 
    44 int ffind(int s)
    45 {
    46     if(f[s]!=-1) return f[s];
    47     f[s]=INF;
    48         for(int i=1;i<=n;i++) if((1<<i-1)&s)
    49         {
    50             for(int j=i+1;j<=n;j++) if((1<<j-1)&s)
    51             {
    52                 int ss=get_s(i,j,s);
    53                 if(ss!=-1) f[s]=mymin(f[s],ffind(ss)+1);
    54             }
    55             break;
    56         }
    57             for(int i=1;i<=n;i++) if((1<<i-1)&s)
    58             {
    59                 f[s]=mymin(f[s],ffind(s-(1<<i-1))+1);
    60                 break;
    61             }
    62     return f[s];
    63 }
    64 
    65 int main()
    66 {
    67     int T;
    68     scanf("%d",&T);
    69     while(T--)
    70     {
    71         scanf("%d%d",&n,&m);
    72         for(int i=1;i<=n;i++)
    73         {
    74             double nx,ny;
    75             scanf("%lf%lf",&nx,&ny);
    76             xx[i]=nx;yy[i]=ny;
    77         }
    78         memset(f,-1,sizeof(f));
    79         f[0]=0;
    80         int ans=ffind((1<<n)-1);
    81         printf("%d
    ",ans);
    82     }
    83     return 0;    
    84 }
    View Code

    第二天 100+55+70 哭泣


    被虐的好惨,主要是还是太傻了,其实题目说难也不是很难的。。。。

    上面是bac回的AC代码。。。。

    2016-12-07 14:02:45

  • 相关阅读:
    php 计算时间添加
    微信网页授权
    微信抢红包微信 PHP代码实现
    微信中禁止长按复制的代码
    【转】java内存分配和String类型的深度解析
    【转】java中创建对象的方法
    【转】深入理解Java的接口和抽象类
    【转】Java 字节流与字符流的区别
    【转】Java并发编程:Thread类的使用
    【转】深入理解java异常处理机制
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6140942.html
Copyright © 2011-2022 走看看