Codeforces Round #286 (Div. 1) A,B,D题解

终于上橙了...说起来有点小意外..本来看不会做打算用小号做Div.2的,然后我开错浏览器交到大号了...造成的结果就是拿命去调试B.幸好最后过了

【AC代码见题解最下方】

----------------------------------------------------------------------------------------------------------------------------------------------------------------------

A.Mr. Kitayuta, the Treasure Hunter

有30001个岛屿,0到30000。你从0出发,给你第一次跳的距离d。若某次跳的距离为k,则以后每次都只能跳k+1,k,k-1。某些岛屿有宝藏。问你遵照跳跃规则,最多可以拿到多少宝藏。



当时抱着反正做了A也会掉分的心态所以没做。其实就是个水DP。我们用f[i][j]表示在第i的位置,跳的距离是d+j。注意到这里j的范围很小。-300到+300就可以。【最多只能变换那么多次】因为j可以是负数我们可以整体加上300。然后直接转移即可

----------------------------------------------------------------------------------------------------------------------------------------------------------------------

B.Mr. Kitayuta's Technology

输入n和m。表示共有n个点,m对关系。每对关系(s,t)表示s可以到达t。【有向】
问你最多加入多少条有向边才可以满足所有的m对关系。




看到这题第一反应就是tarjan缩点。先把强联通分量内部连起来再把强联通分量之间练起来。然后WA掉了。后来手画样例的时候发现强联通分量之间有的连接是不需要加边的。首先我们把所有强联通分量内部都连成一个环。如果这个强联通分量有k个点,则连k条边【k>=2】。然后对于两个k>=2都的强联通分量,我们可以不加边就把他们连成一个大环【断边然后重组】。最后我们再加上所有k=1的强联通分量就可以了。
----------------------------------------------------------------------------------------------------------------------------------------------------------------------





这题真是做题经验的碾压。感觉别人都是第一眼看过去就知道怎么做了,我拿着题解还看了半天。
首先,直接用并查集的话复杂度是O(qm)
那么我们可以想想怎么优化
1、对于节点数>√m的颜色,那么我们可以通过q来暴力统计。因为这样的颜色最多√m个,所以复杂度O(q√m)
2、对于节点数<=√m的颜色,如果有k个节点,我们可以内部k^2来暴力统计,用map存下结果【大概就是map[make_pair(s,t)]+=1这样】。最后再用O(q)扫描一遍所有结果加到答案里即可。这样的复杂度是O(m√m)
将上列两种方法复合。则可以在规定时间内出解
【维护连通性的时候我用的并查集,因为每次都要O(n)初始化一遍所以TLE了。后来把初始化写进了函数里终于卡了过去。最慢的一个点3997ms】
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
以下附代码:
#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
int f[30001][1001];
int a[30001];
inline int max(int x,int y)
{
     if(x>y)
          return x;
     return y;
}
int main()
{
     int n,d;
     scanf("%d%d",&n,&d);
     int x;
     int i,j;
     for(i=1;i<=n;i++)
     {
          scanf("%d",&x);
          a[x]++;
     }
     for(i=0;i<=30000;i++)
          for(j=0;j<=600;j++)
               f[i][j]=-2100000000;
     f[d][300]=a[d];
     for(i=d+1;i<=30000;i++)
     {
          for(j=1;j<=599;j++)
          {
          	   if(i-(d+j-300)>=0&&(d+j-300)>0)
          	   {
                    f[i][j]=max(max(f[i-(d+j-300)][j],f[i-(d+j-300)][j+1]),f[i-(d+j-300)][j-1])+a[i];
                   /* if(j-1>=0)
                         f[i][j]=max(f[i-(d+j-300)][j-1],f[i][j]);
                    f[i][j]+=a[i];*/
               }
          }
     }
     int ans=a[d];
     for(i=1;i<=30000;i++)
          for(j=0;j<=600;j++)
               ans=max(f[i][j],ans);
     printf("%d\n",ans);
     return 0;
}

B. Mr. Kitayuta's Technology
#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
int edge;
int head[300001];
int scc,cnt;
bool v[300001];
int s[400001],top;
int dfn[400001],low[400001],belong[400001];
int indeg[400001],outdeg[400001],sdeg[400001];
struct map
{
     int s,t;
     int next;
}a[300001];
inline void add(int s,int t)
{
	 a[edge].next=head[s];
     head[s]=edge;
     a[edge].s=s;
     a[edge].t=t;
}
inline void tarjan(int d)
{
     int i,x;
     cnt++;
     dfn[d]=cnt;
     low[d]=cnt;
     top++;
     s[top]=d;
     v[d]=true;
     for(i=head[d];i!=0;i=a[i].next)
     {
     	  x=a[i].t;
          if(dfn[x]==0)
          {
               tarjan(x);
               low[d]=min(low[d],low[x]);
          }
          else if(v[x]&&low[d]>dfn[x])
               low[d]=dfn[x];
     }
     if(dfn[d]==low[d])
     {
          scc++;
          x=s[top];
          top--;
          while(x!=d)
          {    
			   v[x]=false;
               belong[x]=scc;
               x=s[top];
               top--;
          }
          v[x]=false;
          belong[x]=scc;
     }
}
inline void count_edge()
{
	 int i,j,d;
     for(i=1;i<=n;i++)
     	  sdeg[belong[i]]++;
}
int father[400001];
int sx[400001];
inline int find(int x)
{
     if(father[x]!=x)
          father[x]=find(father[x]);
     return father[x];
}
inline int count_edgeex()
{
	 int i,j,d;
	 int fx,fy;
	 int s=0;
     for(i=1;i<=n;i++)
     {
          for(j=head[i];j!=0;j=a[j].next)
          {
               d=a[j].t;
               fx=find(belong[i]);
               fy=find(belong[d]);
               if(fx!=fy)
               {
               	    if(sx[fx]==1||sx[fy]==1)
               	         s++;
                    father[fx]=fy;
                    if(sx[fx]!=1||sx[fy]!=1)
                    {
                         sx[fx]+=sx[fy];
                         sx[fy]=sx[fx];
                    }
               }
          }
     }
     return s;
}
int main()
{
     int m;
     scanf("%d%d",&n,&m);
     int i;
     int s,t;
     for(i=1;i<=m;i++)
     {
          scanf("%d%d",&s,&t);
          edge++;
          add(s,t);
     }
     for(i=1;i<=n;i++)
          if(!belong[i])
               tarjan(i);
     count_edge();
     for(i=1;i<=scc;i++)
     {
          father[i]=i;
          sx[i]=sdeg[i];
     }
     int ans=0;
     for(i=1;i<=scc;i++)
          if(sdeg[i]!=1)
               ans+=sdeg[i];
     ans+=count_edgeex();
     /*if(ans>n)
          ans=n;*/
     printf("%d\n",ans);
     return 0;
}

D. Mr. Kitayuta's Colorful Graph
#include<map>
#include<cmath>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
map <pair<int,int>,int> st;
struct line
{
     int s,t,c;
}a[200001];
struct ask
{
     int u,v;
     int x;
}ans[200001];
inline bool cmp(line x,line y)
{
     if(x.c<y.c)
          return true;
     return false;
}
int fa[200001];
inline int find(int x)
{
	 if(fa[x]==0)
	 {
	      fa[x]=x;
	      return fa[x];
	 }
     if(fa[x]!=x)
          fa[x]=find(fa[x]);
     return fa[x];
}
int sx[200001];
bool v[200001];
int main()
{
     int n,m;
     scanf("%d%d",&n,&m);
     int i,j,k,t;
     for(i=1;i<=m;i++)
          scanf("%d%d%d",&a[i].s,&a[i].t,&a[i].c);
     sort(a+1,a+1+m,cmp);
     int q;
     scanf("%d",&q);
     for(i=1;i<=q;i++)
          scanf("%d%d",&ans[i].u,&ans[i].v);
     int td=sqrt(m);
     int fx,fy;
     for(i=1;i<=m;i++)
     {
          for(j=i+1;j<=m;j++)
               if(a[j].c!=a[i].c)
                    break;
          j--;
          //for(k=1;k<=n;k++)
            //   fa[k]=k;
          memset(fa,0,sizeof(fa));
          if(j-i+1>td)
          {
               for(k=i;k<=j;k++)
               {
                    fx=find(a[k].s);
                    fy=find(a[k].t);
                    if(fx!=fy)
                         fa[fx]=fy;
               }
               for(k=1;k<=q;k++)
               {
                    fx=find(ans[k].u);
                    fy=find(ans[k].v);
                    if(fx==fy)
                         ans[k].x++;
			   }
          }
          else
          {
          	   int p=0;
          	   memset(v,false,sizeof(v));
               for(k=i;k<=j;k++)
               {
                    fx=find(a[k].s);
                    if(!v[a[k].s])
                    {
                         p++;
                         sx[p]=a[k].s;
                         v[a[k].s]=true;
                    }
                    fy=find(a[k].t);
                    if(!v[a[k].t])
                    {
                         p++;
                         sx[p]=a[k].t;
                         v[a[k].t]=true;
                    }
                    if(fx!=fy)
                         fa[fx]=fy;
               }
               for(k=1;k<=p;k++)
               {
                    for(t=k+1;t<=p;t++)
                    {
                         if(sx[k]!=sx[t])
                         {
                              fx=find(sx[k]);
                              fy=find(sx[t]);
                              if(fx==fy)
                              {
                                   st[make_pair(sx[k],sx[t])]+=1;
                                   st[make_pair(sx[t],sx[k])]+=1;
                              }
                         }
                    }
               }
          }
          i=j;
     }
     for(i=1;i<=q;i++)
          ans[i].x+=st[make_pair(ans[i].u,ans[i].v)];
     for(i=1;i<=q;i++)
          printf("%d\n",ans[i].x);
     return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值