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

day2018.10.27模擬賽總結

今天應該是day9了吧,前幾天頹廢了沒有怎麼訂題寫部落格.

 

T1:

題目大意:給定一個序列,求序列中每一個數通過±a或者±b得到0的最小操作次數之和.

考場得分:100.

我覺得這道題猜結論很重要啊.

首先顯然每一個數都是獨立不影響其它數的次數的.

那麼看到操作有兩個數就很容易想到歐幾里得,由於求次數所以上擴歐.

我們可以將±a的操作次數設為|x|,±b的操作次數設為|y|,那麼就可以列出標準擴歐式ax+by=c_i.

然後就可以將問題轉化為求這個方程的一個整數解使得|x|+|y|最小.很顯然只要讓兩個數分別為最小非負整數解和最大負整數解取min即可獲得答案.

程式碼如下:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
typedef long long LL;
int n;
LL ans,a,b,c,X,Y,g;
LL exgcd(LL a,LL b,LL &x,LL &y){
  if (b==0){
    x=1;y=0;
    return a;
  }
  LL g=exgcd(b,a%b,x,y),tmp=x;
  x=y;
  y=tmp-a/b*y;
  return g;
}
LL d1(LL x){
  LL y=(c-a*x)/b;
  return abs(x)+abs(y);
}
LL d2(LL y){
  LL x=(c-b*y)/a;
  return abs(x)+abs(y);
}
Abigail into(){
  scanf("%d%lld%lld",&n,&a,&b);
  g=exgcd(a,b,X,Y);
  LL h1=b/g,h2=a/g;
  for (int i=1;i<=n;i++){
    scanf("%lld",&c);
    if (c%g){puts("-1");exit(0);}
    LL x=X*c/g,y=Y*c/g;
    LL g1=x%h1,g2=y%h2;
    g1+=g1<0?h1:0;g2+=g2<0?h2:0;
    LL now=min(min(d1(g1),d1(g1-h1)),min(d2(g2),d2(g2-h2)));
    ans+=now;
  }
}
Abigail outo(){
  printf("%lld\n",ans);
}
int main(){
  freopen("array.in","r",stdin);
  freopen("array.out","w",stdout);
  into();
  outo();
  return 0;
} 

 

T2:

題目大意:給定兩個序列a和b,讓你按照一個任意的順序排列a和b,但是原先的a_ib_i到現在的順序必須是a_jb_j,其中i,j\in [1,n].現在然你求出在求出一個x序列,使得x_i\in[1,n]且不重複,使得a_{x_i}\leq b_{x_j},其中j>i.

考場得分:10.

考場發現按照a,b排序都掛了,然後想離散化b後亂搞也掛了,最後還剩十分鐘寫了個暴力10分收場.

然後正解是按照a+b從大到小排序,然後神奇DP一發,再用線段樹優化一波即可.

具體怎麼做我不會沒聽懂

不願意寫了.

 

T3:

題目大意:給定一張無向帶權圖,以及p個特殊點編號為q_i,讓你求出這個每一個特殊點到距離它最近的特殊點的距離.

考場得分:0.

由於幾天前一直在做最短路的題目,覺得這道題自己應該不會特別慘烈,然後發現這道題並沒有那麼簡單,然後棄掉了...

一開始我的思路是最短路樹來著,然後花了半個小時證明最短路樹是錯誤的,最短路樹上任意兩點在原圖上的最短路並不是在最短路樹上的兩點.

正解是一個十分容易的dijkstra,我們考慮從將每一個特殊點都入堆,然後跑一個dijkstra更新每個點的最短路,而且還要記錄一個點的是從哪個源點拓展過來的.

最後一步需要列舉所有的邊,如果邊的兩端是由不同源點拓展的,就更新這兩個點的答案,這一部具體可以看程式碼.

根據dijkstra演算法的原理,顯然這個演算法是正確的.時間複雜度O(n+mlogm).

程式碼如下:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=200000;
const LL INF=1LL<<60LL;
struct state{
  int x,y;
  LL v;
  state(){x=y=0;v=0LL;}
  state(int X,int Y,LL V){x=X;y=Y;v=V;}
  bool operator > (const state &p)const{return v>p.v;}
};
priority_queue<state,vector<state>,greater<state> >q;
int n,m,p;
struct side{
  int y,next,v;
}e[N*2+9];
int lin[N+9],top;
int u[N+9];
LL dis[N+9],ans[N+9];
int from[N+9],use[N+9];
void ins(int x,int y,int v){e[++top].y=y;e[top].v=v;e[top].next=lin[x];lin[x]=top;}
void dijkstra(){
  for (int i=1;i<=n;i++)
    dis[i]=INF,use[i]=0;
  for (int i=1;i<=p;i++)
    dis[u[i]]=0,from[u[i]]=u[i],q.push(state(u[i],u[i],0));
  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)
      if (dis[e[i].y]>dis[t]+e[i].v){
      	dis[e[i].y]=dis[t]+e[i].v;
      	from[e[i].y]=from[t];
      	q.push(state(e[i].y,from[e[i].y],dis[e[i].y]));
      }
  }
}
Abigail into(){
  scanf("%d%d%d",&n,&m,&p);
  for (int i=1;i<=p;i++) scanf("%d",&u[i]);
  int x,y;
  LL v;
  for (int i=1;i<=m;i++){
    scanf("%d%d%lld",&x,&y,&v);
    ins(x,y,v);ins(y,x,v);
  }
}
Abigail work(){
  dijkstra();
  for (int i=1;i<=n;i++) ans[i]=INF;
  for (int i=1;i<=n;i++)
    for (int j=lin[i];j;j=e[j].next)
      if (from[i]^from[e[j].y]) ans[from[i]]=min(ans[from[i]],dis[i]+dis[e[j].y]+e[j].v);
}
Abigail outo(){
  for (int i=1;i<=p;i++)
    printf("%lld ",ans[u[i]]);
  puts("");
}
int main(){
  freopen("distance.in","r",stdin);
  freopen("distance.out","w",stdout);
  into();
  work();
  outo();
  return 0;
}