day2018.6.22模拟赛总结

T1:

题目大意:

现在有n个宽度为1的矩形.

我们考虑将其中一些宽度为1的矩形取出,按照原顺序再次紧密地靠在一起.

现在,你的任务就是从原图中取出若干个宽度为1的矩形并使用上面的方式组成新的图形,使得新的图形中,内部的最大矩形面积最大.

输出最大面积.

很水的题,大家都A了,可是Rank1好像这题挂了,只有60分.

我的思路就是因为可以删掉任意的矩形.

所以我们可以判断一下高于或等于某个矩形高度的矩形有多少个,然后乘上这个矩形高度,与最大值取最大当结果.

那么我们只需要把矩形按高度排一下序,暴力枚举就行了.

时间复杂度O(Tnlog(n)),算法复杂度瓶颈在于排序.

考场AC代码如下:

#include<bits/stdc++.h>
  using namespace std;
typedef long long LL;
#define ACF inline void
const int N=100000;
LL h[N+1],ma;
int n;
ACF into(){
  ma=0;
  scanf("%d",&n);
  for (int i=1;i<=n;i++)
    scanf("%d",&h[i]);
}
ACF work(){
  sort(h+1,h+n+1);
  for (int i=1;i<=n;i++)
    ma=max(ma,LL(n-i+1)*h[i]);
}
ACF outo(){
  printf("%lld\n",ma);
}
int main(){
  //freopen("rectangle.in","r",stdin);
  //freopen("rectangle.out","w",stdout); 
  int T;
  scanf("%d",&T);
  while (T--){
    into();
    work();
    outo();
  }
  return 0;
}

T2:

题目大意:

有n个人坐成一排,这n个人都在某一个小组中,同一个小组的所有人所坐的位置一定是连续的.

有一个记者在现场进行采访,他每次采访都会询问一个人其所在的小组有多少人,被询问的每个人都给出了正确的答案,但是由于时间仓促,记者不一定询问了每个人,我们记录一个长度为n的答案序列,序列的第i个数表示第i个人的回答,如果为0则表示记者没有询问过这个人.

记者发现,对于一些情况,他可以唯一确定这排所有人的分组,而对于另外一些情况则不能,于是记者开始好奇,对于某一个答案序列,他能不能做到这一点,如果能的话输出1,否则输出0.

这道题好像比较难,结果就是一个计数DP.

用f[i]表示1~i的方案总数,之后用j表示枚举i所在的组的人数,然后用f[i]=f[i-j]的和.

我们让j从i枚举到1,记录一个x,表示最后一个遇到的有数值(数值不是0)的a[j]的数值.

先实时更新x.

更新的过程中,若x不为0且与当前a[j]不相等,说明已经不是一组的了,直接弹出.

若x为0,说明这里都不确定直接加上f[j-1].

若x不为0,我们就要判断这个x与当前i-j+1是否相等,相等则更新.

其次,当f[i]>2时其实没有什么意义,直接f[i]=2就可以了.

也就是说当已经求得f[i]>=2时,直接f[i]=2后弹出就行了.

AC代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define ACF inline void
const int N=1000;
int n,T,a[N+1],f[N+1];
ACF start(){
  for (int i=0;i<=n;i++)
    f[i]=0;
}
ACF into(){
  scanf("%d",&n);
  for (int i=1;i<=n;i++)
    scanf("%d",&a[i]);
}
ACF work(){
  f[0]=1;
  for (int i=1;i<=n;i++)
    for (int j=i,x=0;j>=1;j--){
      if (a[j]){
        if (x&&a[j]&&x!=a[j]) break;
        if (a[j]) x=a[j];
      }
      if (x==0||i-j+1==x){
      	f[i]+=f[j-1];
      	if (f[i]>=2) {
      	  f[i]=2;
      	  break;
      	}
      }
    }
}
ACF outo(){
  if (f[n]==1) printf("1\n");
  else printf("0\n");
}
int main(){
  scanf("%d",&T);
  while (T--){
    start();
    into();
    work();
    outo();
  }
  return 0;
}

T3:

题目大意:

给定一个华容道局面,求出曹操是否可以达到最下面的中间两个,若可以,输出最小步数.

华容道就是某著名游戏,不知道的可以点这里.

这道题就是一道很准的bfs,用一个hash就可以稳稳的AC啦.

不过这里把思路理清一下,首先我们用一个矩阵来存状态,跟输入矩阵不同的是,3~7直接用3或4来存,3表示这个大将是横向的,4表示这个大将是纵向的.

然后我们hash的时候就用一个5进制数来表示,记得用long long,然后用一个set来存.

由于2、3、4的情况会使从同一个状态发展出相同的情况,所以我们可以绘制一张表:

const int tx[5][4]={{},{0,0,0,0},{1,1,0,0},{1,1,0,0},{0,0,0,0}};
const int ty[5][4]={{},{0,0,0,0},{1,0,1,0},{0,0,0,0},{1,0,1,0}};

这张表的作用就是判重.

然后随便搞个方位数组就可以了:

const int x_[4]={0,1,0,-1},y_[4]={1,0,-1,0}

那么主要代码如下:

#include<bits/stdc++.h>
  using namespace std;
typedef long long LL;
#define ACF inline void
const int N=7,M=6;
const int x_d[4]={0,1,0,-1},y_d[4]={1,0,-1,0};
const int tx[5][4]={{},{0,0,0,0},{1,1,0,0},{1,1,0,0},{0,0,0,0}};
const int ty[5][4]={{},{0,0,0,0},{1,0,1,0},{0,0,0,0},{1,0,1,0}};
struct node{
  int a[N][M];
}s;
int n=5,m=4,T,tr[8];
LL hash(node s){
  LL sum=0LL;
  for (int i=n;i>=1;i--)
    for (int j=m;j>=1;j--)
      sum=sum*5+tr[s.a[i][j]];
  return sum;
}
ACF into(){
  for (int i=1;i<=n;i++)
    for (int j=1;j<=m;j++)
      scanf("%d",&s.a[i][j]);
}
ACF work(){
  for(int i=0;i<=n+1;++i)
    s.a[i][0]=s.a[i][m+1]=-1;
  for(int j=0;j<=m+1;++j)
    s.a[0][j]=s.a[n+1][j]=-1;
  for (int i=1;i<=n;i++)
    for (int j=1;j<=m;j++)
      if (s.a[i][j]>=3){
        if (s.a[i][j]==s.a[i+1][j]||s.a[i][j]==s.a[i-1][j]) tr[s.a[i][j]]=3;
        if (s.a[i][j]==s.a[i][j+1]||s.a[i][j]==s.a[i][j-1]) tr[s.a[i][j]]=4;
      }else tr[s.a[i][j]]=s.a[i][j];
}
int bfs(){
  queue < node > q;
  queue < int > qs;
  set < LL > ss;
  q.push(s);qs.push(0);
  ss.insert(hash(s));
  if (s.a[n-1][2]==2&&s.a[n-1][3]==2&&s.a[n][2]==2&&s.a[n][3]==2) return 0;
  while (!q.empty()){
    node s=q.front();
    q.pop();
    int nows=qs.front();
    qs.pop();
    for (int i=1;i<=n;i++)
      for (int j=1;j<=m;j++){
      	int hh=tr[s.a[i][j]],hg=s.a[i][j];
        if (!hh) continue;
        bool flag=1;
        for(int b=0;b<4;++b)
	  flag=(flag&&s.a[i+tx[hh][b]][j+ty[hh][b]]==s.a[i][j]);
        if (!flag) continue;
        for (int e=0;e<4;e++)
          s.a[i+tx[hh][e]][j+ty[hh][e]]=0;
        for (int e=0;e<4;e++){
          int x=i+x_d[e],y=j+y_d[e];
          bool ok=true;
	    for(int b=0;b<4;++b)
	      ok=(ok&&s.a[x+tx[hh][b]][y+ty[hh][b]]==0);
	        if(!ok) continue;
          for (int g=0;g<4;g++)
            s.a[x+tx[hh][g]][y+ty[hh][g]]=hg;
          LL h=hash(s);
	  if (!ss.count(h)){
            q.push(s);
            qs.push(nows+1);
            ss.insert(h);
            if (s.a[n-1][2]==2&&s.a[n-1][3]==2&&s.a[n][2]==2&&s.a[n][3]==2) return nows+1;
	  }
          for (int g=0;g<4;g++)
            s.a[x+tx[hh][g]][y+ty[hh][g]]=0;
        }
        for (int e=0;e<4;e++)
          s.a[i+tx[hh][e]][j+ty[hh][e]]=hg;
      }
  }
  return -1;
}
ACF outo(){
  printf("%d\n",bfs());
}
int main(){
  scanf("%d",&T);
  while (T--){
    into();
    work();
    outo();
  }
}

把y=j+y_d[e]打成y=j+x_d[e]...手残...

万恶的老刘尽然让我写如此丧心病狂之码农题...

害的我的线段树都没写...

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/80775756