noip2013解题报告

国庆想给自己找套题做就看上了这套,然而做的很吃力啊,D2T3至今没有过先强写一波题解

D1T1:https://www.luogu.org/problemnew/show/P1965

转圈游戏,我们先来看10 3 4 5这个样例,针对10和3,我发现只要走10轮3,就跟没走一样,那也就是先求出m,n的最小公倍数,然后快速幂取一下余数,最后剩下t轮,乘一下取一下余就好了。(其实这个地方我写的时候稍微感觉有点问题后来觉得可能没有必要求这个最小公倍数,但神奇的过了)。

#include<stdio.h>
#include<stdlib.h>
long long n,m,k,x,d;
int gcd(long long a,long long b)
{
    if(b==0) d=a;
    else gcd(b,a%b);
    return 0;
}
long long quickpow(long long a,long long b)
{
    long long ans=1;
    while(b!=0)
      {
      if(b%2==1)
        ans=ans*a%d;
      b=b/2;
      a=(a%d)*(a%d)%d;
      }
    return ans%d;
}
int main()
{
    long long t;
    scanf("%lld%lld%lld%lld",&n,&m,&k,&x);
    gcd(m,n);
    d=(m/d)*(n/d);
    t=quickpow(10,k);
    printf("%lld",(x+t*m)%n);
    return 0;
}

D1T2:https://www.luogu.org/problemnew/show/P1966

火柴排队,这题先用不等式知识可以知道什么一定是大的匹配大的,然后通过一通神奇的离散化就行了。

#include<stdio.h>
#include<stdlib.h>
int a[200001]={0},b[200001]={0},r[200001]={0},q[200001]={0},ida[200001]={0},idb[200001]={0};
int n,ans=0;
int quicksort(int x[],int idx[],int left,int right)
{
    int i,j,mid,t;
    i=left;j=right;mid=x[(i+j)/2];
    while(i<=j)
      {
      while(x[i]<mid)  i++;
      while(x[j]>mid)  j--;
      if(i<=j)
        {
        t=x[i];x[i]=x[j];x[j]=t;
        t=idx[i];idx[i]=idx[j];idx[j]=t;
        i++;j--;
        }
      }
    if(i<right)  quicksort(x,idx,i,right);
    if(j>left)   quicksort(x,idx,left,j);
    return 0;
}
int mergesort(int s,int t)
{
    if(s==t)  return 0;
    int mid=(s+t)/2,i=s,k=s,j=mid+1;
    mergesort(s,mid);
    mergesort(mid+1,t);
    while(i<=mid&&j<=t)
      {
      if(q[i]<=q[j])
        {
        r[k]=q[i];k++;i++;
        }
      else
        {
        r[k]=q[j];k++;j++;
        ans+=mid-i+1;ans=ans%99999997;
        }
      }
    while(i<=mid)
      {
      r[k]=q[i];k++;i++;
      }
    while(j<=t)
      {
      r[k]=q[j];k++;j++;
      }
    for(i=s;i<=t;i++)
      q[i]=r[i];
    return 0;
}
int main()
{
    int i,j;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
      {
      scanf("%d",&a[i]);
      ida[i]=i;
      }
    for(i=1;i<=n;i++)
      {
      scanf("%d",&b[i]);
      idb[i]=i;
      }
    quicksort(a,ida,1,n);
    quicksort(b,idb,1,n);
    for(i=1;i<=n;i++)
      q[ida[i]]=idb[i];
    mergesort(1,n);
    printf("%d",ans%99999997);
    return 0;
}

D1T3:https://www.luogu.org/problemnew/show/P1967

这题做的真的扎心,开始写了一个二分答案加强行搜索验证,15分剩余全部TLE,优化半天发现没用,最后一看题解,竟然是先构一个最大生成树,然后在这棵树上针对最小值的最大值进行lca(其实应该是在lca的同时进行维护最小值的最大值),最后求一遍lca即可。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int to[200001]={0},w[200001]={0},nxt[200001]={0},x[200001]={0},y[200001]={0},z[200001]={0},dis[200001][21]={0};
int dep[200001]={0},dp[200001][21]={0},head[200001]={0},father[200001]={0},vis[200001]={0};
int tmp=0,ans=2147483641,n,m,q;
int min(int x,int y)
{
    if(x>y)
      return y;
    else return x;
}
int add(int x,int y,int z)
{
    tmp++;
    to[tmp]=y;
    w[tmp]=z;
    nxt[tmp]=head[x];
    head[x]=tmp;
    return 0;
}
int quicksort(int left,int right)
{
    int i,j,mid,t;
    i=left;j=right;
    mid=z[(i+j)/2];
    while(i<=j)
      {
      while(z[i]>mid)  i++;
      while(z[j]<mid)  j--;
      if(i<=j)
        {
        t=z[i];z[i]=z[j];z[j]=t;
        t=x[i];x[i]=x[j];x[j]=t;
        t=y[i];y[i]=y[j];y[j]=t;
        i++;j--;
        }
      }
    if(i<right)  quicksort(i,right);
    if(j>left)   quicksort(left,j);
    return 0;
}
int find(int x)
{
    if(father[x]!=x)
      father[x]=find(father[x]);
    return father[x];
}
int unit(int r1,int r2)
{
    father[r2]=r1;
    return 0;
}
int lca(int x,int y)
{
    int t,i;
    ans=2147483641;
    if(dep[x]<dep[y])
      {
      t=x;x=y;y=t;
      }
    for(i=20;i>=0;i--)
      {
      if(dep[dp[x][i]]>=dep[y])
        {
        ans=min(ans,dis[x][i]);
        x=dp[x][i];
        }
      if(x==y)
        return ans;
      }
    for(i=20;i>=0;i--)
      if(dp[x][i]!=dp[y][i])
        {
        ans=min(ans,min(dis[x][i],dis[y][i]));
        x=dp[x][i];
        y=dp[y][i];
        }
    ans=min(ans,min(dis[x][0],dis[y][0]));
    return ans;
}
int dfs(int son)
{
    int i,j,t;
    vis[son]=1;
    for(i=0;i<=19;i++)
      {
      dp[son][i+1]=dp[dp[son][i]][i];
      dis[son][i+1]=min(dis[son][i],dis[dp[son][i]][i]);
      }
    for(i=head[son];i;i=nxt[i])
      {
      t=to[i];
      if(vis[t]==1)
        continue;
      dp[t][0]=son;dep[t]=dep[son]+1;
      dis[t][0]=w[i];
      dfs(t);
      }
    return 0;
}
int main()
{
    int i,j,r1,r2;
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++)
      scanf("%d%d%d",&x[i],&y[i],&z[i]);
    quicksort(1,m);
    for(i=1;i<=n;i++)
      father[i]=i;
    for(i=1;i<=m;i++)
      {
      r1=find(x[i]);r2=find(y[i]);
      if(r1!=r2)
        {
         unit(r1,r2);
         add(x[i],y[i],z[i]);
         add(y[i],x[i],z[i]);
        }
      }
    for(i=1;i<=n;i++)
      for(j=0;j<=20;j++)
        dis[i][j]=2147483641;
    for(i=1;i<=n;i++)
      if(vis[i]==0)
        {
        dep[i]=1;
        dfs(i);
        dis[i][0]=2147483641;
        dp[i][0]=i;
        }
    scanf("%d",&q);
    for(i=1;i<=q;i++)
      {
      scanf("%d%d",&x[i],&y[i]);
      if(find(x[i])!=find(y[i]))
        printf("-1\n");
      else
        printf("%d\n",lca(x[i],y[i]));
      }
    return 0;
}

D2T1:https://www.luogu.org/problemnew/show/P1969

积木大赛,很显然这个所谓的最优策略类似于一层一层往下削,但模拟这个过程就显得我很菜尽管确实很菜。那么我是这样想的,假如a[i]>a[i-1],那么我们就可以把处理次数先看为a[i],如果a[i]<a[i-1],那么那么就删掉两个的差值。(想象一下这个过程就是切掉下面几层之后会导致右边会少了)

#include<stdio.h>
#include<stdlib.h>
int a[200001]={0};
int n;
int main()
{
    int i,ans=0;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
      scanf("%d",&a[i]);
    for(i=1;i<=n;i++)
      if(a[i+1]>a[i])
        continue;
      else  
        {
        ans+=a[i];
        ans-=a[i+1];
        }
    printf("%d",ans);
    return 0;
}

D2T2:https://www.luogu.org/problemnew/show/P1970

花匠,据说是个dp,我去年好像做过这题啊,去年我好像想出了dp,今年怎么只会贪心了啊。两遍贪心,直接上代码:

#include<stdio.h>
#include<stdlib.h>
int h[200001]={0},dp[200001]={0};
int n;
int main()
{
    int i,tmp,max=1;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
      scanf("%d",&h[i]);
    dp[1]=h[1];tmp=1;
    for(i=2;i<=n;i++)
      if(tmp%2==1)
        {
        if(h[i]<dp[tmp])
          {
          tmp++;dp[tmp]=h[i];
          }
        else
          dp[tmp]=h[i];
        }
      else 
        {
        if(h[i]>dp[tmp])
          {
          tmp++;dp[tmp]=h[i];
          }
        else dp[tmp]=h[i];
        }
    if(tmp>max)  max=tmp;
    dp[1]=h[1];tmp=1;
    for(i=2;i<=n;i++)
      if(tmp%2==1)
        {
        if(h[i]>dp[tmp])
          {
          tmp++;dp[tmp]=h[i];
          }
        else
          dp[tmp]=h[i];
        }
      else 
        {
        if(h[i]<dp[tmp])
          {
          tmp++;dp[tmp]=h[i];
          }
        else dp[tmp]=h[i];
        }
    if(tmp>max)  max=tmp;
    printf("%d",max);
    return 0;
}

D2T3:https://www.luogu.org/problemnew/show/P1979

华容道可比靶形数独难多了。D2T3也太难了把虽然部分分给的很足,听说是个spfa这玩意不是死了吗,反正我也没看出来,直接暴力广搜,60分。(怎么有dalao裸广搜80分的,加启发式搜索过了也就算了),附上代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int dx[10]={0,1,-1,0,0},dy[10]={0,0,0,1,-1},tex[5000001]={0},tey[500001]={0},tsx[500001]={0},tsy[500001]={0};
int vis1[51][51][51][51]={0},vis[51][51]={0},step[500001]={0},dis[51][51][51][51]={0};
int n,m,q,flag=0;
int main()
{
    int i,j,x,ex,ey,sx,sy,tx,ty,tail,head;
    scanf("%d%d%d",&n,&m,&q);
    for(i=1;i<=n;i++)
      for(j=1;j<=m;j++)
        {
         scanf("%d",&x);
         if(x==0)
           vis[i][j]=1;
        }
    for(i=1;i<=q;i++)
      {
      scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
      if(dis[sx][sy][tx][ty]!=0)
        {
         printf("%d\n",dis[sx][sy][tx][ty]);
         continue;
        }
      memset(tsx,0,sizeof(tsx));memset(tsy,0,sizeof(tsy));
      memset(vis1,0,sizeof(vis1));memset(step,0,sizeof(step));
      memset(tex,0,sizeof(tex));memset(tey,0,sizeof(tey));
      head=0;tail=1;tex[1]=ex;tey[1]=ey;flag=0;
      tsx[1]=sx;tsy[1]=sy;step[1]=0;vis1[ex][ey][sx][sy]=1;
      while(head<tail)
        {
        head++;
        dis[sx][sy][tsx[head]][tsy[head]]=step[head];
        if(tsx[head]==tx&&tsy[head]==ty)
          {
           printf("%d\n",step[head]);
           flag=1;
           break;
          }
        for(j=1;j<=4;j++)
          if(tex[head]+dx[j]>=1&&tex[head]+dx[j]<=n&&tey[head]+dy[j]>=1&&tey[head]+dy[j]<=m)
            {
            tail++;
            if(vis[tex[head]+dx[j]][tey[head]+dy[j]]==1)
              {
              tail--;
              continue;
              }
            if(tex[head]+dx[j]==tsx[head]&&tey[head]+dy[j]==tsy[head])
              {
              tsx[tail]=tex[head];
              tsy[tail]=tey[head];
              tex[tail]=tex[head]+dx[j];
              tey[tail]=tey[head]+dy[j];
              step[tail]=step[head]+1;
              if(vis1[tex[tail]][tey[tail]][tsx[tail]][tsy[tail]]==1)
                {tail--;continue;}
              vis1[tex[tail]][tey[tail]][tsx[tail]][tsy[tail]]=1;
              }
            else
              {
               if(vis1[tex[head]+dx[j]][tey[head]+dy[j]][tsx[head]][tsy[head]]==1)
                 {tail--;continue;}
               vis1[tex[head]+dx[j]][tey[head]+dy[j]][tsx[head]][tsy[head]]=1;
               tex[tail]=tex[head]+dx[j];
               tey[tail]=tey[head]+dy[j];
               tsx[tail]=tsx[head];
               tsy[tail]=tsy[head];
               step[tail]=step[head]+1;
              }
            }
        }
      if(flag==0)
        printf("-1\n");
      }
      return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_40892508/article/details/82932430