2018暑期集训选拔考试题解

前几天把上次考试的题补得差不多了。差最后一题,貌似加上离散化后把原题写炸了,始终没有A掉。等集训一段时间在回头看这题吧。

正好暑期集训即将开始,感觉已经在家咸鱼了一个星期,再不做题怕是要爆零了。。。

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

8月5日更新:最后一题已经AC了~,又干了3个小时。。。

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

A题(智能停车场)(xdoj1334)

模拟,可以按车辆到达时间排个序,然后对于每辆车,直接照车位就可以了。

代码:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long ll;
typedef struct
{
    int s;
    int e;
    int ind;
    int w;
}  Car;
Car p[1010];
Car st[10100];
bool cmp1(Car x,Car y)
{
    if(x.s!=y.s)
    return x.s<y.s;
    return x.ind<y.ind;
}
bool cmp2(Car x,Car y)
{
    return x.ind<y.ind;
}
int a[1010];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
       scanf("%d%d",&p[i].s,&p[i].e);
       p[i].ind=i;
    }
    sort(p+1,p+n+1,cmp1);
    st[0].e=100000;
    for(int i=1;i<=n;i++)
    {
        int ind=i;
        for(int j=1;j<=1000;j++)
        {
            if(p[i].s>=st[j].e)
            {
                ind=j;
                break;
            }
        }
        p[i].w=ind;
        st[ind].e=p[i].e;
    }
    sort(p+1,p+n+1,cmp2);
    printf("%d",p[1].w);
    for(int i=2;i<=n;i++)
    printf(" %d",p[i].w);
    return 0;
}

B题(珂朵莉,威廉和第七兽)(xdoj1327)

直接暴搜,签到题。

代码:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long ll;
char maze[55][55];
int mp[55][55];
int vis[55][55];
int c1,c2,c3,c4=0;
int dx[4]={1,-1,0,0};
int dy[4]={0,0,-1,1};
int n,m;
void dfs(int x,int y,int num)
{
     for(int i=0;i<=4;i++)
     {
         int tx=x+dx[i];
         int ty=y+dy[i];
         if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&mp[tx][ty]==num&&!vis[tx][ty])
         {
              vis[tx][ty]=1;
              dfs(tx,ty,num);       
         }
     }
}
int main()
{
    scanf("%d%d",&n,&m);
    getchar();
    for(int i=1;i<=n;i++)
    {
        scanf("%s",maze[i]);
        getchar();
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(maze[i][j]=='A')
            {
                mp[i][j+1]=1;
            }
            else if(maze[i][j]=='B')
            {
                mp[i][j+1]=2;
            }
            else if(maze[i][j]=='C')
            {
                mp[i][j+1]=3;
            }
            else if(maze[i][j]=='D')
            {
                mp[i][j+1]=4;
            }
        }
    }
//  for(int i=1;i<=n;i++)
//  {
//      for(int j=1;j<=m;j++)
//      printf("%d",mp[i][j]);
//      printf("\n");
//  }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
             if(mp[i][j]==1&&!vis[i][j])
             {
                dfs(i,j,1);
                c1++;
             }
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
             if(mp[i][j]==2&&!vis[i][j])
             {
                dfs(i,j,2);
                c2++;
             }
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
             if(mp[i][j]==3&&!vis[i][j])
             {
                dfs(i,j,3);
                c3++;
             }
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
             if(mp[i][j]==4&&!vis[i][j])
             {
                dfs(i,j,4);
                c4++;
             }
        }
    }
    printf("%d %d %d %d",c1,c2,c3,c4);
    return 0;
}

C题(拿石头的游戏)(xdoj1328)

白书上模板题-硬币游戏

相信学过博弈论后大家对这道题有了刚深入的理解。。。

 代码:

#include<bits/stdc++.h>
using namespace std;
int X,K,A[110];
bool win[10010];
void solve()
{
    win[0]=false;
    for(int j=1;j<=X;j++)
    {
        win[j]=false;
        for(int i=0;i<K;i++)
        {
            win[j] |= A[i] <=j&&!win[j-A[i]];
        }
    }
    if(win[X])
    {
        puts("tsy");
    }
    else
    puts("zxy");
}
int main()
{
    while(scanf("%d%d",&X,&K)!=EOF)
    {
        for(int i=0;i<K;i++)
        scanf("%d",&A[i]);
        solve();
    }
    return 0;
}

 D题(忙碌的周末)(xdoj1333)

CF上原题,这道题关键在于推出这个集合中最多有三个数,分类讨论即可

代码(写的有点丑):

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#include<iostream>
#include<map>
using namespace std;
typedef long long ll;
ll a[200010];
ll pre[100];
map<ll,ll> mp;
int main()
{
    int n;
    int f=0;
       pre[0]=1;
    for(int i=0;i<=33;i++)
    {
        pre[i+1]=2*pre[i];
    }
    while(scanf("%d",&n)!=EOF)
    {
    f=0;    
    ll c[3];
    mp.clear();
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        mp[a[i]]++;
    }
        sort(a+1,a+1+n);
        int cnt;
        for(int i=1;i<=n;i++)
    {
        int u=0;
        c[u++]=a[i];
        cnt=0;
        for(int j=0;j<=34;j++)
        {
            if(mp[a[i]+pre[j]]!=0&&mp[a[i]+2*pre[j]]!=0)
            {
                c[1]=a[i]+pre[j];
                c[2]=a[i]+2*pre[j];
                cnt=2;
            }
              if(cnt==2)
            {
              printf("3\n");
              printf("%lld %lld %lld\n",c[0],c[1],c[2]);        
              f=1;
              break;
            }
        }
        if(f==1)
        {
            break;
        }
    }
    if(f==0)
    {
        for(int i=1;i<=n;i++)
      {
        int u=0;
        c[u++]=a[i];
        cnt=0;
        for(int j=0;j<=34;j++)
        {
            if(mp[a[i]+pre[j]]!=0)
            {
                c[u++]=a[i]+pre[j];
                cnt++;
            }
            if(cnt==1)
            {
              printf("2\n");
              printf("%lld %lld\n",c[0],c[1]);      
              f=1;
              break;
            }
        }
        if(f==1)
        break;
      }
    }
    if(f==0)
    {
        printf("1\n");
        printf("%lld\n",a[1]);
    }
  }
    return 0;
}

E题( 珂朵莉、威廉和第十一兽 )

这道题直接bfs即可,不过需要注意一些特殊情况,特判一下。

代码:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long ll;
typedef struct
{
	int x;
	int y;
	int c;
	int s;
} P;
int mp[110][110];
int vis[110][110];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
char mmp[110][110];
int n,m,t,tx,ty,fx,fy;
int bfs()
{
	queue<P> q;
	P t1;
	t1.c=mp[fx][fy];
	t1.s=0;
	t1.x=fx;
	t1.y=fy;
	q.push(t1);
	while(!q.empty())
	{
		P tt=q.front();
		q.pop();
		if(tt.x==tx&&tt.y==ty)
		return tt.s;
		for(int i=0;i<4;i++)
		{
			 int nx=tt.x+dx[i];
			 int ny=tt.y+dy[i];
			 int pan=(tt.c+1)%t;
			 if(pan==0)
			 pan=t;
			 if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&mp[nx][ny]==pan&&!vis[nx][ny])
			 {
			 	  P t2;
			 	  vis[nx][ny]=1;
			 	  t2.x=nx;
			 	  t2.y=ny;
			 	  t2.c=mp[nx][ny];
			 	  t2.s=tt.s+1;
				  q.push(t2);
			 }
		}
	}
	return -1;
}
int main()
{
	while(scanf("%d%d%d",&n,&m,&t)!=EOF)
	{
	 memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
    {
    	scanf("%s",mmp[i]);
	}
    for(int i=1;i<=n;i++)
    {
    	for(int j=0;j<m;j++)
    	{
    		 mp[i][j+1]=mmp[i][j]-'0';
		}
	}
//	for(int i=1;i<=n;i++)
//	{
//		for(int j=1;j<=m;j++)
//		printf("%d",mp[i][j]);
//		printf("\n");
//	}
	     scanf("%d%d%d%d",&fx,&fy,&tx,&ty);
	     if(t==0)
	 {
	 	printf("-1\n");
	 	continue;
	 }
	     if(!fx||!fy||!tx||!ty)
	    {
	     printf("-1\n");
	     continue;
        }
		int res=bfs();
		if(res==-1)
		printf("-1\n");
		else
		printf("%d\n",res);
	}
	return 0;
}

F题(生命仪式)(xdoj1326)

区间dp,可参考NOIP原题-能量项链,套路是一样的。不过为什么用之前软院新生赛的标程会T掉呢?(滑稽)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[810][810];
ll a[810];
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        memset(dp,0,sizeof(dp));
        memset(a,0,sizeof(a));
        for(int i=1;i<=n;i++)
        {
           scanf("%lld",&a[i]);
           a[n+i]=a[i];
        }
        for(int j=2;j<=2*n;j++)
        {
            for(int i=j-1;i>0&&j-i<n;i--)
            {
                  for(int k=i;k<j;k++)
                  dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+a[i]*a[j+1]*a[k+1]);
            }
        }
        ll ans=0;
        for(int i=1;i<=n;i++)
        ans=max(ans,dp[i][i+n-1]);
        printf("%lld\n",ans);
    }
    return 0;
} 

G题(上海上海上海上海蓬莱蓬莱蓬莱蓬莱 ) (xdoj1329)

听之前想了很长时间也不会,听后秒懂系列。

把B当成-1,把R当成1,维护前缀和,再O(n)扫描一遍即可。

代码:

#include<bits/stdc++.h>
using namespace std;
char s[1100000];
int a[1100000];
int sum[1100000];
int rec[1100000];
int flag[1100000];
int main()
{
    while(scanf("%s",s)!=EOF)
    {
        int len=strlen(s);
        memset(rec,0,sizeof(rec));
        memset(flag,0,sizeof(flag));
        for(int i=0;i<len;i++)
        {
            if(s[i]=='R')
            {
               a[i+1]=1;    
            }
            else
            a[i+1]=-1;
        }
        sum[0]=0;
        rec[0]=0;
        flag[0]=1;
        for(int i=1;i<=len;i++)
        {
            sum[i]=sum[i-1]+a[i];
            if(!flag[sum[i]])
            {
               flag[sum[i]]=1;
               rec[sum[i]]=i;
            }
        }
        int ans=0;
        for(int i=1;i<=len;i++)
        {
            if(flag[sum[i]]!=0)
            {
                ans=max(i-rec[sum[i]],ans);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
 } 

H题(天才琪露诺的完美算数教室 ) (xdoj1330)

打表异或前缀和找规律,这里直接用的题解的思路了,又特判一下0,1,2。不过这道题感觉还没有完全弄懂的样子。。。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    ll t,n;
    scanf("%lld",&t);
    while(t--)
    {
        scanf("%lld",&n);
        if(n==0)
        {
            printf("4 7\n");
        }
        else if(n==1)
        {
            printf("1 5\n");
        }
        else if(n==2)
        {
            printf("3 5\n");
        }
        else
        {
           if(n%4==0)
          {
             printf("%d %lld\n",1,n);
          }
          else if(n%4==1)
          {
              printf("%d %lld\n",2,n-1);
          }
          else if(n%4==2)
          {
            printf("%d %lld\n",2,n);
          }
          else
          {
            printf("%d %lld\n",1,n-1);
          }
        }
    }
    return 0;
 } 

I题(区间第K大)(xdoj1336)

最开始想写二分+BIT,T掉了,而且也有些复杂。后来发现这道题满足区间递增性,用二分加尺取,直接过了。

大致思路就是每次二分时看比这个区间严格大的有多少个,如果这个数比K小就更新答案,不断逼近答案,最后得出解。

代码:

#include<bits/stdc++.h>
using namespace std;  
typedef long long ll;
ll tem[100005];
ll sum[100005]; 
int n,k;
ll cal(ll mid)
{
    int r=1;
    ll res=0;
    for(int i=0;i<n;i++)
    {
        while(r<=n&&sum[r]-sum[i]<=mid)
        r++;
        if(sum[r]-sum[i]<=mid)
        break;
        res+=(n-r+1);       
    }
    return res;
}
int main()
{ 
        int i,j;
        scanf("%d",&n);
        for (i=1;i<=n;i++) 
            scanf("%lld",&tem[i]);
        scanf("%d",&k);
        for (i=1;i<=n;i++)
        {
            sum[i]=sum[i-1]+tem[i]; 
        }
        ll maxx=1e14+10; 
        ll minn=0;  
        ll l=minn,r=maxx;
        ll ans=0;
        while(l<=r)          
        { 
            ll mid=(l+r)>>1;
            if (cal(mid)>=k) 
            l=mid+1;
            else
            {
                r=mid-1;
                ans=mid;
            }
        } 
        printf("%lld\n",ans); 
    return 0;   
}

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

J题  火聚聚铺地毯(xdoj1324)

这道题可以说是poj3171和poj2528的一个结合版,难度加大了不少,在上次比赛中出现在最后一题的位置(不过有几位聚聚做出来了,膜)。首先总体上dp的思路是好想的,可以设dp[i]为到 i 位置的最小花费,易得dp[i]=min(dp[j])+c[i].w;(a[i].l-1<=j<=a[i].r)。可是这么算复杂度是O(n^2),要超时的。因为是区间查询最值问题,想到线段树。用Minv数组维护dp数组,每次查询之前区间的最小值为log(sum),sum为地毯总长度,不过这道题sum过大,线段树存不下,考虑离散化。这道题还需要考虑相邻两个点之间离散化后若相邻,需判断原来两个点是否直接相邻,若不,再中间加一个点(详见代码)。此时sum最高为400000左右,总复杂度nlog(sum), 刚刚好。

代码:

#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
typedef long long ll;
const int maxn = 400010;
int Min[maxn<<2];
void PushUP(int rt) {
       Min[rt] = min(Min[rt<<1] , Min[rt<<1|1]);
}
typedef struct
{
	ll li;
	ll ri;
	int w;
} Cloth;
Cloth c[100010];
Cloth ccopy[100010];
ll lisan[400040];
bool cmp(Cloth x,Cloth y)
{
	if(x.li!=y.li)
	return x.li<y.li;
	return x.ri<y.ri;
}
void build(int l,int r,int rt) {
       Min[rt]=2e9;
       if(l == r)
       return ;
       int m = (l + r) >> 1;
       build(lson);
       build(rson);
}
void update(int p,int sc,int l,int r,int rt) {
       if (l == r) {
              Min[rt] = min(Min[rt],sc);
              return ;
       }
       int m = (l + r) >> 1;
       if (p <= m) update(p , sc , lson);
       else update(p , sc , rson);
       PushUP(rt);
}
int query(int L,int R,int l,int r,int rt) {
       if (L <= l && r <= R) {
              return Min[rt];
       }
       int m = (l + r) >> 1;
       int ret = 2e9;
       if (L <= m) ret = min(ret , query(L , R , lson));
       if (R > m) ret = min(ret , query(L , R , rson));
       return ret;
}
int main() 
{
       int n;
       ll m,e;
       scanf("%d%lld%lld",&n,&m,&e);
       for(int i=0;i<n;i++)
       {
       	    scanf("%lld%lld%d",&c[i].li,&c[i].ri,&c[i].w);
       	    ccopy[i].li=c[i].li;
       	    ccopy[i].ri=c[i].ri;
	   }
	   int tot=0;
	   for(int i=0;i<n;i++)
	   {
	   	    lisan[tot++]=c[i].li;
	   	    lisan[tot++]=c[i].ri;
	   }
	   lisan[tot++]=m;
	   lisan[tot++]=e;
	   sort(lisan,lisan+tot);
	   int num=unique(lisan,lisan+tot)-lisan;
	   int tt=num;
	   for(int i=1;i<=tt;i++)
	   {
	   	   if(lisan[i]-lisan[i-1]>1)
	   	   {
	   	      	lisan[num++]=lisan[i-1]+1;
		   }
	   }
	   sort(lisan,lisan+num);
	   ll mm = lower_bound(lisan,lisan+num,m)-lisan;
	   mm++;
	   ll ee = lower_bound(lisan,lisan+num,e)-lisan;
	   ee++;
	   for(int i=0;i<n;i++)
	   {
	   	   c[i].li=lower_bound(lisan,lisan+num,c[i].li)-lisan;
	   	   c[i].ri=lower_bound(lisan,lisan+num,c[i].ri)-lisan;
	   	   c[i].li++;
	   	   c[i].ri++;
	   }
	   sort(c,c+n,cmp);
	   sort(ccopy,ccopy+n,cmp);
       build(mm-1,ee,1);
	   ll cur=mm-1;
	   update(cur,0,mm-1,ee,1);
	   cur = m-1;
	   int flag=1;
	   for(int i=0;i<n;i++)
	   {
           if(ccopy[i].li>cur+1)
           {
           	   flag=0;
           	   break;
		   }
		   int tem=query(c[i].li-1,c[i].ri,mm-1,ee,1);
		   update(c[i].ri,tem+c[i].w,mm-1,ee,1);
		   cur=max(cur,ccopy[i].ri);
	   }
	   if(e > cur)
	   {
	      printf("-1\n");
          return 0;
       }
	   if(flag)
	   printf("%d\n",query(ee,ee,mm-1,ee,1));
	   else
	   printf("-1\n");
       return 0;
}

猜你喜欢

转载自blog.csdn.net/star_moon0309/article/details/81321834