day2018.11.7模拟赛总结

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

今天的模拟赛打完就可以开始颓到NOIP2018前一个小时了...

T1:

题目大意:给你一个五子棋的下棋序列,让你判定在什么时候结束,谁赢了.

考场得分:100.

每一次处理的时候判定一下就可以了十分容易.

代码如下:

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

#define Abigail inline void
typedef long long LL;

const int N=15;

int a[N+9][N+9],n;

bool check(int x,int y){      //判定是否决出胜负
  int sum=1;
  for (int i=x-1;a[i][y]==a[x][y];--i) ++sum;
  for (int i=x+1;a[i][y]==a[x][y];++i) ++sum;
  if (sum>=5) return 1;
  //行
  sum=1;
  for (int j=y-1;a[x][j]==a[x][y];--j) ++sum;
  for (int j=y+1;a[x][j]==a[x][y];++j) ++sum;
  if (sum>=5) return 1; 
  //列
  sum=1;
  for (int i=x-1,j=y-1;a[i][j]==a[x][y];--i,--j) ++sum;
  for (int i=x+1,j=y+1;a[i][j]==a[x][y];++i,++j) ++sum;
  if (sum>=5) return 1;
  //x-y相等的对角线
  sum=1;
  for (int i=x-1,j=y+1;a[i][j]==a[x][y];--i,++j) ++sum;
  for (int i=x+1,j=y-1;a[i][j]==a[x][y];++i,--j) ++sum;
  if (sum>=5) return 1;
  //x+y相等的对角线 
  return 0;
}

Abigail getans(){
  scanf("%d",&n);
  int x,y;
  for (int i=1;i<=n;++i){
    scanf("%d%d",&x,&y);
    a[x][y]=i&1?1:2;
    if (check(x,y)){
      i&1?printf("A %d\n",i):printf("B %d\n",i);
      break;
    }
    x=y=0;
  }
  if (!x) puts("Tie");
}

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

T2:

题目大意:给定一张无向图,以及k个终点.现在要从点0走到这k个终点,且在当前点会有随机的d条以当前点为一端的边不能走,求在最坏情况下的最短路.

考场得分:75.

扫描二维码关注公众号,回复: 4416885 查看本文章

考场看到这道图论题就感觉比较容易,应该可以拿个高分,然后开始磕.先考虑了若是DAG上的情况,发现从终点开始反着DP即可.然后考虑无向图上,就把DP换成最短路就可以开心的AC这道题了.

然后发现这道题直接写堆优化dijkstra貌似是错误的,貌似必须要用SPFA的多次迭代才能完成,然后就写了一个时间复杂度上限O(nm^2)但实际跑得飞快的SPFA,拿到了75分的高分.

实际上正解是一个被魔改了的dijkstra.我们考虑这道题与普通最短路的区别,发现只是多了一个取d+1短的条件.那么考虑给每一个点维护一个大小不超过d+1的大根堆,存所有dis值已经确定的与这个点相邻的dis值,那么每次更新一个值取堆顶即可.

75分SPFA代码如下:

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

#define Abigail inline void
typedef long long LL;

const int N=100000,M=1000000;
const LL INF=(1LL<<60)-1;

struct side{
  int y,next;
  LL v;
}e[M*2+9];
int lin[N+9],top=1;
int fr[N+9],k,n,m,d;

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

int use[N+9],tt;
LL dis[N+9],tmp[N+9];
queue<int>q;

void SPFA(){
  for (int i=1;i<=n;++i) dis[i]=INF;
  for (int i=1;i<=k;++i){
    dis[fr[i]]=0;
    use[fr[i]]=1;
    q.push(fr[i]);
  }
  while (!q.empty()){
    int t=q.front();q.pop();
    use[t]=0;
    for (int i=lin[t];i;i=e[i].next){
      tt=0;
      for (int j=lin[e[i].y];j;j=e[j].next)
        tmp[++tt]=dis[e[j].y]+e[j].v;
      if (d>=tt) continue;
      nth_element(tmp+1,tmp+d+1,tmp+tt+1);
      if (tmp[d+1]<dis[e[i].y]){
      	dis[e[i].y]=tmp[d+1];
      	if (use[e[i].y]) continue;
        use[e[i].y]=1;
        q.push(e[i].y);
      }
    }
  }
}

Abigail into(){
  scanf("%d%d%d%d",&n,&m,&k,&d);
  int x,y;LL v;
  for (int i=1;i<=m;++i){
    scanf("%d%d%lld",&x,&y,&v);
    ++x;++y;
    ins(x,y,v);ins(y,x,v);
  }
  for (int i=1;i<=k;++i) {
    scanf("%d",&fr[i]);
    ++fr[i];
  }
}

Abigail work(){
  SPFA();
}

Abigail outo(){
  printf("%lld\n",dis[1]==INF?-1:dis[1]);
}

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

100分堆优化dijkstra代码如下:

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

#define Abigail inline void
typedef long long LL;

const int N=100000,M=1000000;
const LL INF=(1LL<<60)-1;

struct side{
  int y,next;
  LL v;
}e[M*2+9];
int lin[N+9],top=1;
int fr[N+9],k,n,m,D;

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

int use[N+9];
LL dis[N+9];
struct node{
  int x;
  LL v;
  node(){}
  node(int X,int V){x=X;v=V;}
  bool operator > (const node &p)const{return v>p.v;}
};
priority_queue<node,vector<node>,greater<node> >q;
priority_queue<LL>d[N+9];

void dijkstra(){
  for (int i=1;i<=n;++i) dis[i]=INF;
  for (int i=1;i<=k;++i){
    dis[fr[i]]=0;
    q.push(node(fr[i],0LL));
  }
  while (!q.empty()){
    int t=q.top().x;q.pop();
    if (use[t]) continue;
    use[t]=1;
    for (int i=lin[t];i;i=e[i].next){
      d[e[i].y].push(dis[t]+e[i].v);
      if (d[e[i].y].size()>D+1) d[e[i].y].pop();
      if (d[e[i].y].size()==D+1&&d[e[i].y].top()<dis[e[i].y]){
      	dis[e[i].y]=d[e[i].y].top();
      	q.push(node(e[i].y,dis[e[i].y]));
      }
    }
  }
}

Abigail into(){
  scanf("%d%d%d%d",&n,&m,&k,&D);
  int x,y;LL v;
  for (int i=1;i<=m;++i){
    scanf("%d%d%lld",&x,&y,&v);
    ++x;++y;
    ins(x,y,v);ins(y,x,v);
  }
  for (int i=1;i<=k;++i) {
    scanf("%d",&fr[i]);
    ++fr[i];
  }
}

Abigail work(){
  dijkstra();
}

Abigail outo(){
  printf("%lld\n",dis[1]==INF?-1:dis[1]);
}

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

T3:

题目大意:给定一个序列A以及一个常数k,并定义一个子段的平均值为:

\frac{(max_{i=l}^{r}A[i])-(min_{i=l}^{r}A[i])}{r-l+k}

现在要求这个序列的平均值最大的长度在[L,R]的子段的平均值.

考场得分:50.

考场发现自己只会暴力,然后用线段树优化了一波,时间复杂度为O(n(logn+R-L+1)).

正解先提出了一个性质,若没有长度限制的话,那么最大平均值子段的最大值和最小值一定为这个子段的两端.

有了这个性质,我们就可以愉快地将平均值的式子写成:

\frac{A[r]-A[l]}{r-l+k}

突然优美了许多,我们只需要再设a数组为A数组的差分数组,就可以将式子写成:

\frac{\sum_{i=l}^{n}a[i]-a[i-1]}{r-l+k}

那么考虑二分ans,然后就可以得出,若这个上式大于ans,则ans一定偏小.

那么维护一下这个式子就可以了,时间复杂度O(nlog(ans)).

代码太神了不敢写了.(其实是太懒了)

猜你喜欢

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