【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

原文地址:https://www.cnblogs.com/Konjakmoyu/p/6140942.html