Croc Champ 2013 - Round 1 题解

A:水题

B:水题,只需要记录连得边数的点的个数即可轻易判断

C:个人觉得是一个比较蛋疼的题,开始还看错了,以为不允许出现0,>_<。dfs枚举长度,枚举0~l/2的数字,后半部分即可统计出来。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=15;
int n,tot,a[N],c[N],p[N],w[N],ans[100005][N];
void cnt(int k,int pos,int l)
{
   if(k<0)
   {
      if(pos==l) memmove(ans[tot++],c,sizeof(c));
      return; 
   }
   c[k]=0;
   for(int i=pos;i<=l-1-k && i<=pos+2;++i)
   {
      c[k]=c[k]*10+p[i];
      if((p[pos]>0 || c[k]==0 && i==pos) && c[k]<=255 && i>=l-1-k*3)
      cnt(k-1,i+1,l);
   }
}
inline void dfs(int pos,int l)
{
   int i;
   if((pos+1-(l&1)>(l>>1)))
   {
      for(i=0;i<n;++i)  if(!w[i]) break;
	if(i==n) cnt(3,0,l);
	return;  
   }
   for(i=0;i<n;++i)
   {
      ++w[i];
      p[pos]=p[l-1-pos]=a[i];
      dfs(pos+1,l);
      --w[i];
   }
}
int main()
{
	int i,j;
      scanf("%d",&n);
	if(n>6) {printf("0");return 0;}
      for(i=0;i<n;++i) scanf("%d",&a[i]);
	sort(a,a+n);
	for(i=max(4,n);i<=12;++i)
	{
	   memset(p,0,sizeof(p));
	   dfs(0,i);
	}
	printf("%d\n",tot);
	for(i=0;i<tot;++i)
	 for(j=3;j>=0;--j)
	  printf("%d%c", ans[i][j], (j?'.':'\n'));
	return 0;
}

D:并查集,不错的题。点数很少,边数很多,意味着可能有好多边添加后完全不影响连通性,删除这样的边完全不影响结果。于是我们只需记录下从前面开始影响连通性的编号,后面同理。每次查询时处理即可

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int N=505,M=10005;
int a[M],b[M],qi[M],ho[M],f[505];
int find(int x)
{
    if(f[x]==x) return x;
    else return f[x]=find(f[x]);
}
int main()
{
      int i,j,n,m,k;
      scanf("%d%d",&n,&m);
      for(i=1;i<=n;++i) f[i]=i;
      int h,r;h=r=0;
      for(i=1;i<=m;++i)  
      {
         scanf("%d%d",&a[i],&b[i]);
         int fa=find(a[i]);
         int fb=find(b[i]);  
         if(fa!=fb)
         {
            f[fb]=fa;
            qi[++h]=i;
         }
      }
      for(i=1;i<=n;++i) f[i]=i;
      for(i=m;i>=1;--i)
      {
         int fa=find(a[i]);
         int fb=find(b[i]);
         if(fa!=fb)
         {
           f[fb]=fa;  
           ho[++r]=i;
         }
      }
      scanf("%d",&k);
      while(k--)
      {
        int x,y;
        scanf("%d%d",&x,&y);
        for(i=1;i<=n;++i) f[i]=i;
        for(i=1;i<=h;++i)
        {
          if(qi[i]<x) f[find(b[qi[i]])]=find(a[qi[i]]);
          else break;
        }
        for(i=1;i<=r;++i)
        {
          if(ho[i]>y) f[find(b[ho[i]])]=find(a[ho[i]]);
          else break;
        }
        int ans=0;
        for(i=1;i<=n;++i) if(f[i]==i) ans++;
        printf("%d\n",ans);
      return 0;
}
E:线段树,我实现略渣,lazy标记总下错。只需要开始记录线段树每个区间最左面对应的a数组的值及是否覆盖过,查询,修改时下放标记即可

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值