Codeforces Round #408 (Div. 2) B. C.D.

来源:互联网 发布:ssh权限管理系统源码 编辑:程序博客网 时间:2024/06/05 07:50

B:
题目大意:

给你N个盒子,第一个盒子一开始装着骨头,现在有m个位子上有漏洞,如果带有骨头的盒子移动到了这些位子上,那么骨头就会掉在漏洞上再也不会动。

问最终骨头在哪里、

每一次操作交换两个位子上的盒子。

自己的代码被hack了..其实只要动当前为ans的就可以了

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int vis[1000050];int a[1000050];int main(){    int n,m,k;    while(~scanf("%d%d%d",&n,&m,&k))    {        memset(vis,0,sizeof(vis));        for(int i=0;i<m;i++)        {            int x;            scanf("%d",&x);            vis[x]=1;        }        int ans=1;        while(k--)        {            int x,y;            scanf("%d%d",&x,&y);            if(x==ans)            {                if(vis[x]!=1)ans=y;            }            else if(y==ans)            {                if(vis[y]!=1)ans=x;            }        }        printf("%d\n",ans);    }}

C:

题目链接:http://codeforces.com/contest/796/problem/C题目的意思是有n个点,n-1条边,现在让你任选一个点当做起点,去掉这个点,然后和这个点连接的所有的点的权值都加一,然后所有和那个点相连的点的点的点权也要加一,有点绕,慢慢理解,1->2->3,就是说去掉123的点权都要加一,然后问你最大集合中的最小点权。

心得:想法其实差不多,但是我wa了..

我打算dfs随便一个mx来比较与cmx ,mx 的距离.但其实这样是不可以的;
比如下面的话应该从2开始走的,
(所以正确的做法应该是按照题解一样,mx 的相邻的节点都应该是mx或者是cmx.)
自己wa的数据
Input

3
2 2 2
3 2
1 2

Participant’s output

4

Jury’s answer

3

参考http://blog.csdn.net/bless924295/article/details/70244270

#include <cstdio>#include <cstring>#include <iostream>#include <vector>#define inf 0x3f3f3f3fusing namespace std;int a[400000];vector<int >G[400000];int n;int solve(){    int x=0,y=0;    int maxval=-inf;    for(int i=1;i<=n;i++){        if(a[i]>maxval)            maxval=a[i];    }    for(int i=1;i<=n;i++){        if(a[i]==maxval)            x++;        if(a[i]==maxval-1)            y++;    }    int xx=x;    int yy=y;    bool flag1=true;    bool flag2=true;    for(int i=1;i<=n;i++){        bool flag3=true;        if(a[i]==maxval)            x--;        else if(a[i]==maxval-1)            y--;        for(int j=0;j<(int )G[i].size();j++){            if(a[G[i][j]]==maxval){                x--;                flag3=false;            }            if(a[G[i][j]]==maxval-1)                y--;        }        if(x==0){            flag1=false;            if(y==0&&flag3)                flag2=false;        }        x=xx,y=yy;    }    if(!flag1){        if(flag2==0)            return maxval;        else            return maxval+1;    }    return maxval+2;}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++){        scanf("%d",&a[i]);    }    for(int i=0;i<n-1;i++){        int u,v;        scanf("%d%d",&u,&v);        G[u].push_back(v);        G[v].push_back(u);    }    int ans=solve();    cout<<ans<<endl;    return 0;}

D:
参考http://blog.csdn.net/mengxiang000000/article/details/70146788

题目大意:给你一个树,其中有N个点,N-1条无向边,现在有M个特殊点,问你最多可以切割多少条边,使得每个普通点到最近的特殊点的距离小于等于d.保证有解。

体悟:一开始以为是树dp,结果怎么想都想不出来..
原来就只是个多点bfs而已…
贪心地使得每个点都被遇见一次…因为是树,如果第二次遇到,那么这条边是不用的,

#include<stdio.h>#include<string.h>#include<queue>#include<vector>using namespace std;struct node{    int to,pos;}now,nex;vector<node >mp[300800];int vis[300800];int ans[300800];int main(){    int n,m,k;    while(~scanf("%d%d%d",&n,&m,&k))    {        queue<int >s;        memset(vis,0,sizeof(vis));        memset(ans,0,sizeof(ans));        for(int i=1;i<=n;i++)mp[i].clear();        for(int i=0;i<m;i++)        {            int x;            scanf("%d",&x);            s.push(x);            vis[x]=1;        }        for(int i=1;i<=n-1;i++)        {            int x,y;            scanf("%d%d",&x,&y);            now.to=y;            now.pos=i;            mp[x].push_back(now);            now.to=x;            now.pos=i;            mp[y].push_back(now);        }        while(!s.empty())        {            int u=s.front();            s.pop();            for(int i=0;i<mp[u].size();i++)            {                int v=mp[u][i].to;                if(vis[v]==0)                {                    ans[mp[u][i].pos]=1;                    vis[v]=1;                    s.push(v);                }            }        }        int cnt=0;        for(int i=1;i<=n-1;i++)if(ans[i]==0)cnt++;        printf("%d\n",cnt);        for(int i=1;i<=n-1;i++)        {            if(ans[i]==0)printf("%d ",i);        }        printf("\n");    }}

E:待补:http://codeforces.com/contest/796/problem/E dp
..

解题报告:  考虑用f[i][j][x][y]表示考虑完前i个问题,当前总共用了j次机会,对于第一个人还能看x道题,第二个人还能看y道题的最优值,考虑x和y等于0的情况,直接转移就好了。  这里写转出可能会方便一些。  注意到这个复杂度是O(npk2)的,但是当p>2∗nk时,可以全选,那么直接全选就好了,特判一下,所以复杂度是O(n2k)。

心得:这个地方还是挺难想到这个状态的。。
要记录左边,右边还可以看多少次。。看了多少次,看到第几题。。。这样的话满足了dp 的要求。。
别人的代码:

    #include<queue>      #include<cstdio>      #include<string>      #include<cstring>      using namespace std;      int f[2][1005][55][55];      int a[1005],b[1005];      int main()      {          int n,p,k;          scanf("%d%d%d",&n,&p,&k);          if(p>2*(n+k-1)/k)              p=2*(n+k-1)/k;          int n1,n2,x;          scanf("%d",&n1);          int i,j;          for(i=1;i<=n1;i++)          {              scanf("%d",&x);              a[x]=1;          }          scanf("%d",&n2);          for(i=1;i<=n2;i++)          {              scanf("%d",&x);              b[x]=1;          }          int y;          memset(f,-127/3,sizeof(f));          f[0][0][0][0]=0;          int p1=1,p2=0;          for(i=1;i<=n;i++)          {              for(j=0;j<=p;j++)              {                  for(x=0;x<k;x++)                  {                      for(y=0;y<k;y++)                      {                          if(y!=0)                              f[p1][j+1][k-1][y-1]=max(f[p1][j+1][k-1][y-1],f[p2][j][x][y]+(a[i]||b[i]));                          else                              f[p1][j+1][k-1][0]=max(f[p1][j+1][k-1][0],f[p2][j][x][y]+a[i]);                          if(x!=0)                              f[p1][j+1][x-1][k-1]=max(f[p1][j+1][x-1][k-1],f[p2][j][x][y]+(a[i]||b[i]));                          else                              f[p1][j+1][0][k-1]=max(f[p1][j+1][0][k-1],f[p2][j][x][y]+b[i]);                          if(x!=0&&y!=0)                              f[p1][j][x-1][y-1]=max(f[p1][j][x-1][y-1],f[p2][j][x][y]+(a[i]||b[i]));                          else if(x!=0)                              f[p1][j][x-1][0]=max(f[p1][j][x-1][0],f[p2][j][x][y]+a[i]);                          else if(y!=0)                              f[p1][j][0][y-1]=max(f[p1][j][0][y-1],f[p2][j][x][y]+b[i]);                          else                              f[p1][j][0][0]=max(f[p1][j][0][0],f[p2][j][x][y]);                      }                  }              }              p1=1-p1;              p2=1-p2;              for(j=0;j<=p;j++)                  for(x=0;x<k;x++)                      for(y=0;y<k;y++)                          f[p1][j][x][y]=-100000;          }          int ans=0;          for(j=0;j<=p;j++)              for(x=0;x<k;x++)                  for(y=0;y<k;y++)                      ans=max(ans,f[p2][j][x][y]);          printf("%d\n",ans);          return 0;      }