1. 程式人生 > >day2018.11.7模擬賽總結

day2018.11.7模擬賽總結

今天的模擬賽打完就可以開始頹到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.

考場看到這道圖論題就感覺比較容易,應該可以拿個高分,然後開始磕.先考慮了若是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)).

程式碼太神了不敢寫了.(其實是太懶了)