day2018.11.6模拟赛总结

版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/83786986

颓了这么多天,终于重新开始写模拟赛blog了.

诶今天是模拟赛day几来着???


T1:

题目大意:给定一个矩阵表示A,若A_{i,j}为0表示i,j为空地,为1表示障碍.再给出一个移动序列LRUD分别表示向左向右向上向下.问最少去掉几个移动序列的字符可以使得移动不出边界且不经过障碍.

考场得分:100.

数据可以支持O(n^3)的算法,所以考虑DP,而且很显然这是一个DP,所以直接设f[k][i][j]表示移动序列上到第k个字符,目前在网格上的坐标为(i,j)的最多保留字符数量.

发现状态k只会影响到状态k+1,所以可以用f[k][i][j]更新状态f[k+1][i][j]f[k+1][i+x[k+1]][j+y[k+1]],并用滚动数组优化.

代码如下:

#include<bits/stdc++.h>
  using namespace std;

#define Abigail inline void
typedef long long LL;

const int N=400,INF=(1<<29)-1;

int ri(){
  int x=0;
  char c=getchar();
  for (;c<'0'||c>'9';c=getchar());
  for (;c<='9'&&c>='0';c=getchar()) x=x*10+c-'0';
  return x;
}

char rc1(){
  char c=getchar();
  while (c<'0'||c>'9') c=getchar();
  return c;
} 

char rc2(){
  char c=getchar();
  while (c<'A'||c>'Z') c=getchar();
  return c;
}

int f[2][N+9][N+9],use[2][N+9][N+9],old,now,ans;
int b[N+9][N+9],x[N+9],y[N+9],n,m,k;

Abigail into(){
  n=ri();m=ri();k=ri();
  for (int i=1;i<=n;++i)
    for (int j=1;j<=m;++j)
      b[i][j]=rc1()-'0';
  for (int i=1;i<=k;++i)
    switch (rc2()){
      case 'L':
      	x[i]=0;y[i]=-1;
        break;
      case 'R':
      	x[i]=0;y[i]=1;
      	break;
      case 'U':
      	x[i]=-1;y[i]=0;
        break;
      case 'D':
      	x[i]=1;y[i]=0;
      	break;
    }
}

Abigail work(){
  for (int i=1;i<=n;++i)
    b[i][0]=b[i][m+1]=1;
  for (int i=1;i<=m;++i)
    b[0][i]=b[n+1][i]=1;
  old=1;now=0;
  use[old][1][1]=1;
  f[old][1][1]=0;
  for (int g=0;g<k;++g){
    for (int i=1;i<=n;++i)
      for (int j=1;j<=m;++j)
        use[now][i][j]=f[now][i][j]=0;
    for (int i=1;i<=n;++i)
      for (int j=1;j<=m;++j)
        if (use[old][i][j]){
          f[now][i][j]=max(f[now][i][j],f[old][i][j]);
          use[now][i][j]=1;
          if (b[i+x[g+1]][j+y[g+1]]) continue;
          use[now][i+x[g+1]][j+y[g+1]]=1;
          f[now][i+x[g+1]][j+y[g+1]]=max(f[now][i+x[g+1]][j+y[g+1]],f[old][i][j]+1);
        }
    now^=1;old^=1;
  }
  for (int i=1;i<=n;++i)
    for (int j=1;j<=m;++j)
      if (use[old][i][j]) ans=max(ans,f[old][i][j]);
}

Abigail outo(){
  printf("%d\n",k-ans);
}

int main(){
  freopen("island.in","r",stdin);
  freopen("island.out","w",stdout);
  into();
  work();
  outo();
  return 0;
} 

T2:

题目大意:给出一串序列,现在问这个序列的第k小区间和为多少.

考场得分:100分.

考场想了一小时,写了5分钟...

其实看到这种没什么数学模型,与数据结构和图论明显没什么关系的题就可以直接考虑DP和分治了.然后这道题DP想不到任何有用的性质,就考虑二分了.

很自然地想到二分第k小的区间和,然后用一个O(n^2)的暴力枚举区间来判定,优秀地做到了O(n^2logSUM)比直接枚举区间还要慢的算法.

考虑优化,我们考虑枚举区间的右端点r,很容易发现若左端点为l时满足条件,那么属于区间[l,r-1]的区间一定都满足条件,所以考虑二分维护,可以做到优秀的O(nlog^2n)的算法.

然而这样还是不能做到满分.那么考虑枚举右端点r时,左端点l也一直往右移,那么直接维护l即可.时间复杂度O(nlogn).

代码如下:

#include<bits/stdc++.h>
  using namespace std;

#define Abigail inline void
typedef long long LL;

const int N=1000000;
const LL INF=(1LL<<62)-1LL;

LL a[N+9],sum[N+9],ans,k;
int n;

int ri(){
  int x=0;
  char c=getchar();
  for (;c<'0'||c>'9';c=getchar());
  for (;c<='9'&&c>='0';c=getchar()) x=x*10+c-'0';
  return x;
}

int rl(){
  LL x=0;
  char c=getchar();
  for (;c<'0'||c>'9';c=getchar());
  for (;c<='9'&&c>='0';c=getchar()) x=x*10+c-'0';
  return x;
}

bool check(LL mid){
  int last=1;LL ans=0;
  for (int i=1;i<=n;++i){
    while (sum[i]-sum[last-1]>mid) last++;
    ans+=i-last+1;
  }
  return ans>=k;
}

Abigail into(){
  n=ri();k=rl();
  for (int i=1;i<=n;++i){
    a[i]=rl();
    sum[i]=sum[i-1]+a[i];
  }
}

Abigail work(){
  ans=INF;
  for (int i=61;i>=0;--i)
    if (check(ans-(1LL<<i))) ans-=1LL<<i;
}

Abigail outo(){
  printf("%lld\n",ans);
}

int main(){
  freopen("movie.in","r",stdin);
  freopen("movie.out","w",stdout);
  into();
  work();
  outo();
  return 0;
} 

T3:

题目大意:给定一棵树,以及若干点集,要求将点集中的点分成几个组,每个组只有两个点,使得每组的两点在树上的距离最小是否小于树的总点数,若小于输出方案.

考场得分:35分.(写链的部分分说是15分实际有35分贼开心^o^)

这道题貌似跟蓝书上的异象石很像啊,都用到了同一个结论.(然而我还是想了1个小时都不会)

首先我们考虑链的部分分,就可以发现距离一定不会超过树的总点数,并且一定是相邻两点分一组.

然后我们像异象石这题的做法一样,将所有点按照dfs序来排序,就可以发现:

\sum_{i}^{s} dis(a_i,a_i+1)\leq 2(n-1)

其中ai为询问的点集,并且设a_{s+1}=a_1.

所以两点之间连边肯定是取排序后相邻两点,那么就只会有两种不同的方案,在这两种方案里面必定有一种距离和小于等于n-1,那么取小的那种就可以了.

代码如下:

#include<bits/stdc++.h>
  using namespace std;

#define Abigail inline void
typedef long long LL;

const int N=200000;

struct side{
  int y,next;
}e[N*2+9];
int lin[N+9],top,n;

void ins(int x,int y){
  e[++top].y=y;
  e[top].next=lin[x];
  lin[x]=top;
}

struct node{
  int deep,dfn,top,fa,size,son;
}d[N+9];
int num=0;

void dfs1(int k,int fa){
  d[k].fa=fa;
  d[k].deep=d[fa].deep+1;
  d[k].size=1;
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y^fa){
      dfs1(e[i].y,k);
      d[k].size+=d[e[i].y].size;
      if (d[d[k].son].size<d[e[i].y].size) d[k].son=e[i].y;
    }
}

void dfs2(int k,int top){
  d[k].top=top;
  d[k].dfn=++num;
  if (d[k].son) dfs2(d[k].son,top);
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y^d[k].fa&&e[i].y^d[k].son) dfs2(e[i].y,e[i].y);
}

int LCA(int x,int y){
  while (d[x].top^d[y].top)
    d[d[x].top].deep>d[d[y].top].deep?x=d[d[x].top].fa:y=d[d[y].top].fa;
  return d[x].deep<d[y].deep?x:y;
}

int s,tmp[N+9];

bool cmp(const int &a,const int &b){return d[a].dfn<d[b].dfn;}

Abigail into(){
  scanf("%d",&n);
  int x,y;
  for (int i=1;i<n;++i){
    scanf("%d%d",&x,&y);
    ins(x,y);ins(y,x);
  }
}

Abigail work(){
  dfs1(1,0);
  dfs2(1,1);
}

Abigail getans(){
  #define dis(a,b) d[a].deep+d[b].deep-2*d[LCA(a,b)].deep
  while (~scanf("%d",&s)&s){
    for (int i=1;i<=s;++i)
      scanf("%d",&tmp[i]);
    sort(tmp+1,tmp+1+s,cmp);
    int sum=0;
    sum+=dis(tmp[1],tmp[s]);
    for (int i=2;i<s;i+=2)
      sum+=dis(tmp[i],tmp[i+1]);
    puts("Yes");
    if (sum<n){
      printf("%d %d\n",tmp[1],tmp[s]);
      for (int i=2;i<s;i+=2)
        printf("%d %d\n",tmp[i],tmp[i+1]);
    }else{
      for (int i=1;i<s;i+=2)
       printf("%d %d\n",tmp[i],tmp[i+1]);
    }
  }
}

int main(){
  freopen("kieru.in","r",stdin);
  freopen("kieru.out","w",stdout);
  into();
  work();
  getans();
  return 0;
}

猜你喜欢

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