noip2014 小结

D1T1 水水的模拟。。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
int a[500]={0},b[500]={0};
int ju(int aa,int bb)
{
    if (aa==0)
    {
         if (bb==0) return 0;
         if (bb==1) return -1;
         if (bb==2) return 1;
         if (bb==3) return 1;
         if (bb==4) return -1;
    }
    if (aa==1)
    {
         if (bb==0) return 1;
         if (bb==1) return 0;
         if (bb==2) return -1;
         if (bb==3) return 1;
         if (bb==4) return -1;     
    }
    if (aa==2)
    {
         if (bb==0) return -1;
         if (bb==1) return 1;
         if (bb==2) return 0;
         if (bb==3) return -1;
         if (bb==4) return 1;
    }
    if (aa==3)
    { 
         if (bb==0) return -1;
         if (bb==1) return -1;
         if (bb==2) return 1;
         if (bb==3) return 0;
         if (bb==4) return 1;
    }
    if (aa==4)
    {
         if (bb==0) return 1;
         if (bb==1) return 1;
         if (bb==2) return -1;
         if (bb==3) return -1;
         if (bb==4) return 0;
    }
}
int main()
{
    freopen("rps.in","r",stdin);
    freopen("rps.out","w",stdout);
    
    int ansa=0,ansb=0,na,nb,n,i,j,ca=0,cb=0,ans=0;
    scanf("%d%d%d",&n,&na,&nb);
    for (i=1;i<=na;++i)
      scanf("%d",&a[i]);
    for (i=1;i<=nb;++i)
      scanf("%d",&b[i]);
    ca=0;cb=0;
    for (i=1;i<=n;++i)
    {
        ca=ca%na+1;
        cb=cb%nb+1;
        ans=ju(a[ca],b[cb]);
        if (ans==1)
          ++ansa;
        if (ans==-1)
          ++ansb;
    }
    printf("%d %d
",ansa,ansb);
    
    return(0);
    
    fclose(stdin);
    fclose(stdout);
}
View Code

D1T2 水水的树形dp(可是考试的时候写残了,建错了树,以后一定要深搜建树。)

有一点小技巧:每次保存这个节点的孩子的价值之和、孩子中价值的最大值和次大值(求最大值时节省时间)。(fye大神写错了最大值和次大值的更新竟然A了。。。全省第8!!!)

还是有一点小问题,就是在求节点的孩子的价值之和的时候也要%10007,不然就会超过int

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
struct use{
     int va,maxi,maxii,sum;
}tree[200001];
int ans=0,maxn=0,next[400001]={0},point[200001]={0},en[400001]={0};
bool visit[200001]={false};
void work(int i)
{
     int y,k,j=0;
     y=point[i];
     while(y!=0)
     {
          if (!visit[en[y]])
          {
            visit[en[y]]=true;
           work(en[y]);
           if (tree[en[y]].va>=tree[i].maxi) 
           { 
             tree[i].maxii=tree[i].maxi;
             tree[i].maxi=tree[en[y]].va;
           }
           else
           {
             if (tree[en[y]].va>tree[i].maxii&&tree[en[y]].va<tree[i].maxi)
                   tree[i].maxii=tree[en[y]].va;
           }
           ans=(ans+(tree[i].sum*tree[en[y]].va)%10007)%10007;
           tree[i].sum=(tree[i].sum+tree[en[y]].va)%10007;
           ans=(ans+(tree[i].va*tree[en[y]].sum)%10007)%10007;
           if (tree[en[y]].maxi*tree[i].va>maxn)
             maxn=tree[en[y]].maxi*tree[i].va;
           if (tree[i].maxi*tree[i].maxii>maxn)
             maxn=tree[i].maxi*tree[i].maxii;
         }
         y=next[y];
     }
}
int main()
{
    freopen("link.in","r",stdin);
    freopen("link.out","w",stdout);
    
    int n,i,j,u,v,tot=0;
    memset(tree,0,sizeof(0));
    scanf("%d",&n);
    for (i=1;i<n;++i)
    {
        scanf("%d%d",&u,&v);
        ++tot;
        next[tot]=point[u];
        point[u]=tot;
        en[tot]=v;
        ++tot;
        next[tot]=point[v];
        point[v]=tot;
        en[tot]=u;
    }
    for (i=1;i<=n;++i)
      scanf("%d",&tree[i].va);
    visit[1]=true;
    work(1);
    ans=((ans%10007)*2)%10007;
    printf("%d %d
",maxn,ans);

    return(0);
    
    fclose(stdin);
    fclose(stdout);
}
View Code

D1T3 小小的dp(考试的时候写了nm^2的算法,竟然有wa,只得了60。关键是当时想到了完全背包的优化,敲了一遍又删了。。。ZUO啊)

从当前节点(i-1)更新下一节点(i)会好做一些,但是有个顺序问题,先从当前(i-1)跳一次到下一个(i),再更新从当前的位置跳了多次(及i这个位置),最后更新从上面往下落得情况。。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
struct use{
    int p,l,h;
}guan[10001];
int x[10001]={0},y[10001]={0},f[10001][1001];
int my_comp(const use &a,const use &b)
{
    if (a.p<b.p) return 1;
    else return 0;
}
int main()
{
    freopen("bird.in","r",stdin);
    freopen("bird.out","w",stdout);
    
    int i,j,n,m,k,st,en,fl,ci,p,lj,maxn,maxx,ans,hh;
    bool ff=false;
    memset(f,127,sizeof(f));
    maxx=f[0][0];
    maxn=2100000000;
    scanf("%d%d%d",&n,&m,&k);
    for (i=0;i<n;++i)
      scanf("%d%d",&x[i],&y[i]); 
    for (i=1;i<=k;++i)
        scanf("%d%d%d",&guan[i].p,&guan[i].l,&guan[i].h);
    sort(guan+1,guan+k+1,my_comp);
    for (i=1;i<=m;++i)
      f[0][i]=0;
    fl=1;
    for (i=1;i<=n;++i)
    {
      ans=maxx;
      st=1;en=m;
      if (guan[fl].p==i) 
      {
         st=guan[fl].l+1;
         if (guan[fl].h==m)
           en=m;
         else
           en=guan[fl].h-1;
         ++fl;
      }
      if (st==0) st=1; 
      for (j=1;j<=m;++j)
      {
        if (f[i-1][j]>maxn) continue;
        hh=min(j+x[i-1],m);
        f[i][hh]=min(f[i][hh],f[i-1][j]+1);
        if (ans>f[i][hh]) ans=f[i][hh];
      }
      for (j=1;j<=m;++j)
      {
        if (f[i][j]>maxn) continue;
        hh=min(j+x[i-1],m);
        f[i][hh]=min(f[i][hh],f[i][j]+1);
        if (f[i][hh]<ans) ans=f[i][hh];
      }
      for (j=1;j<=m;++j)
      {
          if (f[i-1][j]>maxn) continue;
          hh=j-y[i-1];
          if (hh<=0) continue;
          f[i][hh]=min(f[i][hh],f[i-1][j]);
          if (f[i][hh]<ans) ans=f[i][hh];
      }
      if (ans>maxn)
        {
            ff=true;
            ci=fl-2;
            break;
        }
      for (j=0;j<st;++j)
        f[i][j]=maxx;
      for (j=en+1;j<=m;++j)
        f[i][j]=maxx;
    }
    if (ff) printf("0
%d
",ci);
    else printf("1
%d
",ans);
    
    return(0);
    
    fclose(stdin);
    fclose(stdout);
}
View Code

D2T1 水水的。。。这该叫什么?

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
int map[150][150]={0};
int main()
{
    freopen("wireless.in","r",stdin);
    freopen("wireless.out","w",stdout);
    
    int n,x,y,u,ansi=0,dd,x1,x2,y1,y2,i,j,p,q,maxx=0,maxy=0;
    long long ans=0,sum;
    scanf("%d",&dd);
    scanf("%d",&n);
    for (i=1;i<=n;++i)
    {
        scanf("%d%d%d",&x,&y,&u);
        map[x][y]=u;
        if (x>maxx) maxx=x;
        if (y>maxy) maxy=y;
    }
    maxx=maxx+dd; if (maxx>128) maxx=128;
    maxy=maxy+dd; if (maxy>128) maxy=128;
    ansi=1;
    for (i=0;i<=maxx;++i)
      for (j=0;j<=maxy;++j)
      {
          x1=i-dd;
          if (x1<0) x1=0;
          x2=i+dd;
          if (x2>128) x2=128;
          y1=j-dd;
          if (y1<0) y1=0;
          y2=j+dd;
          if (y2>128) y2=128;
          sum=0;
          for (p=x1;p<=x2;++p)
            for (q=y1;q<=y2;++q)
              sum+=map[p][q];
          if (sum==ans)
            ++ansi;
          else
          {
             if (sum>ans)
             {
               ans=sum;
               ansi=1;
             }
          }
      }
    printf("%d %lld
",ansi,ans);
    
    
    fclose(stdin);
    fclose(stdout);
    return(0);
}
View Code

D2T2 水水的深搜、最短路

考试的时候又写残了。。。(我与第二题。。。有个美丽的约定)(当时竟然深搜最短路,我的脑子里面。。。装了些啥。。。)

存的就是整个图的反图,然后先深搜一遍,将所有终点能到的点标记,然后对于不能到的点进行这个反图中这个点出发的边的终点进行去点,这是递归的,因为可能去掉很多个点(不一定是一直去点,要判断这个点本身能不能到)。(有点。。。我的语文啊)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
int next[400001]={0},point[10001]={0},en[400001]={0},dis[10001]={0},que[1000001]={0};
bool visit[10001]={false},cut[10001]={false};
void dfs(int i,int dep)
{
     int j;
     visit[i]=true;
     if (dis[i]>dep)
       dis[i]=dep;
     j=point[i];
     while(j!=0)
     {
         if (!visit[en[j]]) dfs(en[j],dep+1);
         j=next[j];
     }
}
void work(int i)
{
     int j;
     cut[i]=true;
     if (visit[i]) return;
     j=point[i];
     while (j!=0)
     {
         if (!cut[en[j]]) work(en[j]);
         j=next[j];
     }
}
int main()
{
    freopen("road.in","r",stdin);
    freopen("road.out","w",stdout);
    
    int n,m,i,j,k,s,t,u,v,maxn=0,head,tail,x,y;
    bool ff=false;
    maxn=1000000;
    scanf("%d%d",&n,&m);
    for (i=1;i<=m;++i)
    {
        scanf("%d%d",&u,&v);
        next[i]=point[v];
        point[v]=i;
        en[i]=u;
    }
    scanf("%d%d",&s,&t);
    for (i=1;i<=n;++i)
      dis[i]=maxn;
    dfs(t,0);
    if (!visit[s]) ff=true;
    else
    {
        for (i=1;i<=n;++i)
          if (!visit[i]) 
            work(i);
        for (i=1;i<=n;++i)
          dis[i]=maxn;
        memset(visit,false,sizeof(visit));
        head=0;tail=1;que[1]=t;visit[t]=true;dis[t]=0;
        do{
            head=head%1000000+1;
            x=que[head];
            visit[x]=false;
            y=point[x];
            while (y!=0)
            {
                if (!cut[en[y]])
                {
                    if (dis[x]+1<dis[en[y]])
                    {
                        dis[en[y]]=dis[x]+1;
                        if (!visit[en[y]])
                        {
                            tail=tail%1000000+1;
                            que[tail]=en[y];
                            visit[en[y]]=true;
                        }
                    }
                }
                y=next[y];
            }
        }while(head!=tail);
        if (cut[s]||dis[s]==maxn) ff=true;
    }
    if (ff) printf("-1
");
    else printf("%d
",dis[s]);
    
    fclose(stdin);
    fclose(stdout);
    
    return(0);
}
View Code

 D2T3 高大上的解方程

这个数据范围。。。醉了。。。考试的时候直接放弃掉了,写了30的代码。(有过写50分的冲动,但是想到超级复杂的各种高精度,于是,及时收手)。

这个题目的神奇正解,下面来分析一下(金策)。

数学上的引例:f(x)=0(%p)则f(x+p)=0(%p);

有了这个积累,就相对简单了。取多个小质数,暴力算出1~p-1中的f(x),然后穷举1~m,看一下%不同质数之后的结果是否都为0,如果是就是答案了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxm 1000000
using namespace std;
int ans[maxm]={0},pre[5][maxm]={0},n,ci[5][maxm]={0},pi[5]={11261,19997,22877,21893,14843},
    ai[5][maxm]={0};
char ss[maxm];
bool judge(int x){
    for (int i=0;i<5;++i)
      if (ci[i][x%pi[i]]!=0) return false;
    return true;
}
int main(){
    int m,i,j,l,k;bool f;
    scanf("%d%d",&n,&m);
    for (i=0;i<=n;++i){
        scanf("%s",&ss);
        l=strlen(ss);f=false;
        if (ss[0]=='-'){f=true;j=1;}
        else j=0;
        for(j;j<l;++j)
            for (k=0;k<5;++k)
                ai[k][i]=(ai[k][i]*10+ss[j]-'0')%pi[k];
        if (f)
            for (k=0;k<5;++k) ai[k][i]=pi[k]-ai[k][i];
    }for (k=0;k<5;++k)
        for (i=1;i<pi[k];++i){
            pre[k][0]=1;
            for (j=1;j<=n;++j) pre[k][j]=pre[k][j-1]*i%pi[k];
            for (j=0;j<=n;++j) ci[k][i]=(ci[k][i]+ai[k][j]*pre[k][j])%pi[k];
        }
    for (i=1;i<=m;++i)
        if (judge(i)) ans[++ans[0]]=i;
    printf("%d
",ans[0]);
    for (i=1;i<=ans[0];++i) printf("%d
",ans[i]);
}
View Code

noip2014就这样“轰轰荡荡”的过去了,今年的内心几经沉浮,最后看到自己的成绩的时候,一点小庆幸,当然以后不会有这么好的运气了,要真正能在考场上考出水准,离不开平日里多下功夫。明年就要迎来第一次省选了,希望能不留遗憾。

下面来说一说考场上的。。。错误:1)无奈的建错了树,这种错误在平时遇到过,却没有借鉴;2)竟然用dfs求最短路,检查的时候也没查出来,竟然还有点得意的往上交,这种基础的问题不应该出现问题,以后要时刻警惕;3)要在考场上想出好的算法,然后实现,不能因为语言问题阻碍了自己的发挥,要在平时多练基础题,提高代码能力,加快手速、保证正确率,正确理解到代码的运行原理,避免不必要的错误。

要多下功夫了!!!加油!!!

原文地址:https://www.cnblogs.com/Rivendell/p/4109090.html