zoukankan      html  css  js  c++  java
  • 【noip 2015】提高组

    先扔一份写的超级详细的题解。   -Day1-    -Day2-  

    (感觉自己并没有什么写题解的必要啊……做点补充好了,顺便扔代码

    D1T1.神奇的幻方

    题目链接

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 int n,a[41][41];
     6 int main()
     7 {
     8     scanf("%d",&n);
     9     int mid=n/2+1,x=1,y=mid;
    10     a[1][mid]=1;
    11     for(int i=2;i<=n*n;i++)
    12     {
    13         if(x==1&&y!=n)x=n,y++;
    14         else if(x!=1&&y==n)x--,y=1;
    15         else if(x==1&&y==n)x++;
    16         else
    17         {
    18             if(a[x-1][y+1])x++;
    19             else x--,y++;
    20         }
    21         a[x][y]=i;
    22     }
    23     for(int i=1;i<=n;i++)
    24     {
    25         for(int j=1;j<=n;j++)
    26             printf("%d ",a[i][j]);
    27         printf("
    ");
    28     }
    29     return 0;
    30 }
    View Code

    D1T2.信息传递

    题目链接

    拓扑排序,找到最短环的长度。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int N=200050;
     6 int n,to[N],in[N],ans=0x3f3f3f3f;
     7 bool f[N];
     8 int read()
     9 {
    10     int x=0,f=1;char c=getchar();
    11     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    12     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    13     return x*f;
    14 }
    15 int main()
    16 {
    17     n=read();
    18     for(int i=1;i<=n;i++)
    19         to[i]=read(),in[to[i]]++;
    20     for(int i=1;i<=n;i++)
    21         if(in[i]==0)in[to[i]]--;
    22     for(int i=1;i<=n;i++)
    23     {
    24         if(in[i]==0||f[i])continue;
    25         int st=i,ed=i,sum=0;
    26         f[i]=true;
    27         while(to[ed]!=st)
    28             sum++,ed=to[ed],f[ed]=true;
    29         ans=min(ans,sum+1); 
    30     }
    31     printf("%d",ans); 
    32     return 0;
    33 }
    View Code

    D1T3.斗地主

    题目链接

    一道真·很不想写的题。留个坑?回来填坑了。

    比想象中的好写……其实就是dfs,vijos上的100组数据是真的有意思orz

    注意A的转换,以及三带二不能带双王。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 using namespace std;
     5 const int inf=0x3f3f3f3f;
     6 int T,n,x,y,ans,num[20],a[5]; 
     7 int read()
     8 {
     9     int x=0,f=1;char c=getchar();
    10     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    11     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    12     return x*f;
    13 }
    14 int go()
    15 {
    16     bool f=false;
    17     if(num[0]==2)f=true;
    18     memset(a,0,sizeof(a));
    19     for(int i=0;i<=13;i++)a[num[i]]++;
    20     int sum=0;
    21     while(a[4]&&a[2]>=2)a[4]--,a[2]-=2,f=false,sum++;
    22     while(a[4]&&a[1]>=2)a[4]--,a[1]-=2,sum++;
    23     while(a[4]&&a[2])a[4]--,a[2]--,f=false,sum++;
    24     if(f)sum++,a[2]--;
    25     while(a[3]&&a[2])a[3]--,a[2]--,sum++;
    26     while(a[3]&&a[1])a[3]--,a[1]--,sum++;
    27     return sum+a[1]+a[2]+a[3]+a[4];
    28 }
    29 void dfs(int step)
    30 {
    31     if(step>=ans)return;
    32     int t=go();
    33     ans=min(ans,t+step);
    34     for(int i=2;i<=13;i++)
    35     {
    36         int next=i;
    37         while(num[next]>=3)next++;
    38         if(next-i>=2)
    39         {
    40             for(int j=i+1;j<=next-1;j++)
    41             {
    42                 for(int k=i;k<=j;k++)num[k]-=3;
    43                 dfs(step+1);
    44                 for(int k=i;k<=j;k++)num[k]+=3;
    45             }
    46         }
    47     }
    48     for(int i=2;i<=13;i++)
    49     {
    50         int next=i;
    51         while(num[next]>=2)next++;
    52         if(next-i>=3)
    53         {
    54             for(int j=i+2;j<=next-1;j++)
    55             {
    56                 for(int k=i;k<=j;k++)num[k]-=2;
    57                 dfs(step+1);
    58                 for(int k=i;k<=j;k++)num[k]+=2;
    59             }
    60         }
    61     }
    62     for(int i=2;i<=13;i++)
    63     {
    64         int next=i;
    65         while(num[next]>=1)next++;
    66         if(next-i>=5)
    67         {
    68             for(int j=i+4;j<=next-1;j++)
    69             {
    70                 for(int k=i;k<=j;k++)num[k]--;
    71                 dfs(step+1);
    72                 for(int k=i;k<=j;k++)num[k]++;
    73             }
    74         }
    75     }
    76 }
    77 int main()
    78 {
    79     T=read();n=read();
    80     while(T--)
    81     {
    82         memset(num,0,sizeof(num));
    83         for(int i=1;i<=n;i++)
    84         {
    85             x=read();y=read();
    86             if(x==1)x=13;
    87             else if(x)x--; 
    88             num[x]++;
    89         }
    90         ans=inf;
    91         dfs(0);
    92         printf("%d
    ",ans);
    93     }
    94     return 0;
    95 }
    View Code

    D2T1.跳石头

    题目链接

    其实我第一次看到这道题的时候它叫河中跳房子……

    先二分出答案,再判断答案是否合法(即需要移走的岩石数是否小于等于M

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 int len,n,m,ans,a[50010];
     6 int read()
     7 {
     8     int x=0,f=1;char c=getchar();
     9     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    10     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    11     return x*f;
    12 }
    13 bool check(int mid)
    14 {
    15     int base=0,num=0;
    16     for(int i=1;i<=n+1;i++)
    17     {
    18         if(a[i]-base<mid)num++;
    19         else base=a[i];
    20     }
    21     return num<=m;
    22 }
    23 int main()
    24 {
    25     len=read();n=read();m=read();
    26     for(int i=1;i<=n;i++)a[i]=read();
    27     a[n+1]=len;
    28     int l=1,r=len;
    29     while(l<=r) 
    30     {
    31         int mid=(l+r)>>1;
    32         if(check(mid))ans=mid,l=mid+1;
    33         else r=mid-1; 
    34     }
    35     printf("%d",ans);
    36     return 0;
    37 }
    View Code

    D2T2.子串

    题目链接

    DP状态转移方程及解析详见开头题解(其实只是因为懒

    这里提供自己写的一份滚动数组版本的代码。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int modd=1000000007;
     6 const int N=1005;
     7 const int M=205;
     8 int n,m,K,f[2][M][M],s[2][M][M];
     9 char a[N],b[M];
    10 int read()
    11 {
    12     int x=0,f=1;char c=getchar();
    13     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    14     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    15     return x*f;
    16 }
    17 int main()
    18 {
    19     n=read();m=read();K=read();
    20     scanf("%s%s",a,b);
    21     s[0][0][0]=s[1][0][0]=1;
    22     for(int i=1;i<=n;i++)
    23     {
    24         int ii=i%2;
    25         for(int j=1;j<=m;j++)
    26             if(a[i-1]==b[j-1])
    27                 for(int k=1;k<=min(j,K);k++)
    28                 {
    29                     f[ii][j][k]=(s[ii^1][j-1][k-1]+f[ii^1][j-1][k])%modd;
    30                     s[ii][j][k]=(s[ii^1][j][k]+f[ii][j][k])%modd;
    31                 }
    32             else
    33                 for(int k=1;k<=min(j,K);k++)
    34                 {
    35                     f[ii][j][k]=0;
    36                     s[ii][j][k]=s[ii^1][j][k];
    37                 }
    38     }
    39     printf("%d",s[n%2][m][K]);
    40     return 0;
    41 }
    View Code

    D2T3.运输计划

    题目链接

    我们的大体思路依然是二分答案 → 判断是否合法。

    首先,建树,dfs一发。因为我们后面需要树上倍增求最近公共祖先,所以要把一些会用到的信息先处理好。

    需要特别注意的是,我们用v[i]代表结点i与其父亲结点的连边的权值

    然后,我们把每个运输计划起点、终点的LCA以及路径长度先预处理出来。

    对于二分出来的每个ans,我们可能需要将一条边边权赋为0来使所有方案的路径长度都小于或等于ans。倘若ans合法,则这条边满足以下条件:位于所有路径长度大于ans的计划的路径交集里,且权值大于路径长度最长的那条边-ans的值。否则ans不合法。

    我们选择用sum数组维护树上前缀和来求交集,sum[i]代表结点i与其父亲结点的连边在所有路径长度大于ans的计划中出现的次数。若sum[i]=路径长度大于ans的计划的数量,则结点i与其父亲结点的连边在交集里。二分答案之后的判定过程为:O(m)扫一遍方案,对于所有路径长度大于我们二分出来的ans的方案,起点、终点sum+1,他们的LCAsum-2,然后再求前缀和。至于为什么要这么做……画图易得:如果结点i与其父亲结点的连边在方案x中,则方案x的起点或终点有且只有一个在结点i的子树内。然后就很简单明了了

    具体实现看代码咯。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int N=700010;
     6 int n,m,cnt,a,b,t;
     7 int head[N],fa[N],deep[N],dis[N],x[N][20],st[N],ed[N],lca[N],dist[N],sum[N],v[N];
     8 bool f[N];
     9 struct edge{int next,to,w;}e[N];
    10 int read()
    11 {
    12     int x=0,f=1;char c=getchar();
    13     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    14     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    15     return x*f;
    16 }
    17 void insert(int u,int v,int w)
    18 {
    19     cnt++;e[cnt].to=v;e[cnt].w=w;e[cnt].next=head[u];head[u]=cnt;
    20 }
    21 void dfs(int k)
    22 {
    23     f[k]=true;
    24     for(int i=1;(1<<i)<=deep[k];i++)
    25         x[k][i]=x[x[k][i-1]][i-1];
    26     for(int i=head[k];i;i=e[i].next)
    27     {
    28         if(!f[e[i].to])
    29         {
    30             x[e[i].to][0]=k;
    31             deep[e[i].to]=deep[k]+1; 
    32             v[e[i].to]=e[i].w;
    33             dis[e[i].to]=dis[k]+e[i].w;
    34             dfs(e[i].to);
    35         }
    36     }
    37 }
    38 int find(int ri,int rj)
    39 {
    40     if(deep[ri]<deep[rj])swap(ri,rj);
    41     int d=deep[ri]-deep[rj]; 
    42     for(int i=0;(1<<i)<=d;i++)
    43         if((1<<i)&d)ri=x[ri][i];
    44     if(ri==rj)return ri;
    45     for(int i=16;i>=0;i--)
    46         if((1<<i)<=deep[rj]&&x[ri][i]!=x[rj][i])
    47             ri=x[ri][i],rj=x[rj][i];
    48     return x[ri][0];
    49 }
    50 void query(int k)
    51 {
    52     for(int i=head[k];i;i=e[i].next)
    53         if(e[i].to!=x[k][0])
    54         {
    55             query(e[i].to);
    56             sum[k]+=sum[e[i].to];
    57         }
    58 }
    59 bool check(int ans)
    60 {
    61     int cntt=0,cutt=0;
    62     for(int i=1;i<=n;i++)sum[i]=0;
    63     for(int i=1;i<=m;i++)
    64         if(dist[i]>ans)
    65         {
    66             cntt++;cutt=max(cutt,dist[i]-ans);
    67             sum[st[i]]++;sum[ed[i]]++;sum[lca[i]]-=2;
    68         }
    69     query(1);
    70     for(int i=1;i<=n;i++)
    71         if(sum[i]==cntt&&v[i]>=cutt)return true;
    72     return false;
    73 }
    74 int main()
    75 {
    76     n=read();m=read();
    77     for(int i=1;i<n;i++)
    78     {
    79         a=read();b=read();t=read();
    80         insert(a,b,t);insert(b,a,t);
    81     }
    82     dfs(1);
    83     for(int i=1;i<=m;i++)
    84     {
    85         st[i]=read();ed[i]=read();
    86         lca[i]=find(st[i],ed[i]);
    87         dist[i]=dis[st[i]]+dis[ed[i]]-2*dis[lca[i]];
    88     }
    89     int L=0,R=0;
    90     for(int i=1;i<=m;i++)R=max(R,dist[i]);
    91     while(L<=R)
    92     {
    93         int mid=(L+R)>>1;
    94         if(check(mid))R=mid-1;
    95         else L=mid+1;
    96     }
    97     printf("%d
    ",L);
    98     return 0;
    99 }
    View Code
  • 相关阅读:
    Myeclipse导出war包
    报表移动端如何进行移动设备绑定与撤销
    MySQL检查运行的mysqld服务器是否支持OpenSSL
    JavaScript替换字符串中最后一个字符
    dns 添加域名
    连接linux系统sftp下载文件
    8.1 Optimization Overview
    Chapter 8 Optimization
    19.6.1 Partitioning Keys, Primary Keys, and Unique Keys 分区键,主键,和唯一健
    Web报表页面如何传递中文参数
  • 原文地址:https://www.cnblogs.com/zsnuo/p/7147102.html
Copyright © 2011-2022 走看看