day2018.6.28模拟赛总结

我个zz我连扩欧都不会了...


T1:

题目大意:b+ia=d+jc中,b,a,c,d都为正整数,解出i的最小正整数解,并输出b+ia,若无解输出-1.

我好菜啊我竟然把扩展欧几里得忘了,考场花了一个小时推出来的...

题目中的式子我们可以转换成ia-jc=d-b.

然后用扩欧求解就可以了.

我在想什么我竟然把c设成了负数...

考场代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define ACF inline void
typedef long long LL;
LL a,b,c,d,x,y,g,l;
LL exgcd(LL a,LL b,LL &x,LL &y){
  if (!b){
    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;
}
ACF into(){
  scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
}
ACF work(){
  c=-c;
  g=exgcd(a,c,x,y);
}
ACF outo(){
  if (d==b) printf("0\n");
  else if ((d-b)%g) printf("-1\n");
    else {
      l=c/g;
      x*=(d-b)/g;y*=(d-b)/g;
      if (x<0) x+=(-x)/l*l;
      while (x<0) x+=l;
      x-=(x/l)*l;
      while (x-l>=0) x-=l;
      printf("%lld\n",b+x*a);
    }
}
int main(){
  //freopen("run.in","r",stdin);
  //freopen("run.out","w",stdout);
  into();
  work();
  outo();
  return 0;
} 

AC代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define ACF inline void
typedef long long LL;
LL a,b,c,d,x,y,g,l;
LL exgcd(LL a,LL b,LL &x,LL &y){
  if (!b){
    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;
}
ACF into(){
  scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
}
ACF work(){
  g=exgcd(a,c,x,y);
}
ACF outo(){
  if (d==b) printf("0\n");
  else if ((d-b)%g) printf("-1\n");
    else {
      l=c/g;
      x*=(d-b)/g;
      x=(x%l+l)%l;
      printf("%lld\n",b+x*a);
    }
}
int main(){
  //freopen("run.in","r",stdin);
  //freopen("run.out","w",stdout);
  into();
  work();
  outo();
  return 0;
}


T2:

题目大意:有一些客人,每个客人有一个坐标(xi,yi),还有一个di表示di秒匀速走一个单位长度,现在给出每个客人的xi,yi,di,每个客人还有1的宽度,也就是说每个客人占了(xi,yi)到(xi+1,yi)这些位置.

现在,每个客人i都会到达y轴,并且若只要有一秒同时没有一个客人k在(0,yk)满足yk<yi,则会被记录下来,求记录下来的客人有几个.

注:n<=50000    1<=di<=10^5.

这道题好像很难,考场上暴力写不出来,果断报复社会(交了一个死循环卡时)...

正解的思路就是利用所有客人的两个事件点——一个进入y轴,一个走出y轴,先提前算出来.

然后按照事件点的时间为第一关键字,y轴位置为第二关键字从小到大排序.

之后建立一个set,表示这个点当前是否位于0的位置.

然后枚举一遍所有事件点,直接对这个set进行操作即可.

存下来一个人是否出现过也用一个set来实现就行了.

AC代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define ACF inline void
typedef long long LL;
const int N=50000;
pair< int , int >e[N*2+2];
int n,top;
set< int > s,ss;
ACF into(){
  scanf("%d",&n);
  int x,y,d;
  for (int i=1;i<=n;i++){
    scanf("%d%d%d",&x,&y,&d);
    x*=-d;
    e[++top].first=x-d;e[top].second=y;
    e[++top].first=x;e[top].second=-y;
  }
}
ACF work(){
  sort(e+1,e+1+top);
  for (int i=1;i<=top;){
    int j=i;
    for (;j<=top&&e[i].first==e[j].first;j++)
      if (e[j].second>0) s.insert(e[j].second);
      else s.erase(-e[j].second);
    if (!s.empty()) ss.insert(*s.begin());
    i=j;
  }
}
ACF outo(){
  printf("%d\n",ss.size());
}
int main(){
  //freopen("watch.in","r",stdin);
  //freopen("watch.out","w",stdout);
  into();
  work();
  outo();
  return 0;
}


T3

题目大意:现在有一棵树,树上有n个节点和m条链可以选择占领,占领的每条链之间不能重合,要求得分最大.

注:1<=n,m<=10^5.

这道题本来在考场上写了40分链的数据,然后挂掉了.

现在也不知道是什么错误,下面是错误代码:

#include<bits/stdc++.h>
  using namespace std;
#define ACF inline void
const int N=100000;
const int INF=1000000000;
struct seg{
  int l,r,v;
}e[N+1];
int n,m,f[N+1];
ACF into(){
  scanf("%d%d",&n,&m);
  int x,y;
  for (int i=1;i<n;i++)
    scanf("%d%d",&x,&y);
  for (int i=1;i<=m;i++)
    scanf("%d%d%d",&e[i].l,&e[i].r,&e[i].v);
}
bool cmp(seg a,seg b){
  return a.r<b.r;
}
ACF work(){
  sort(e+1,e+1+m,cmp);
  int j=1;
  for (int i=1;i<=n;i++){
    f[i]=f[i-1];
    for (;e[j].r==i;j++)
      f[i]=max(f[i],f[e[j].l-1]+e[j].v);
  }
}
ACF outo(){
  printf("%d\n",f[n]);
} 
int main(){
  //freopen("occupy.in","r",stdin);
  //freopen("occupy.out","w",stdout);
  into();
  work();
  outo();
  return 0;
} 

正解是用f[i][0]表示以i为根的子树不占领根的最优解,f[i][1]是占领的最优解.

后者较为简单,直接统计所有儿子的结果就可以了.

前者则需要枚举链,枚举的是两端的lca是当前结点i的链.

然后dp方程就是.

其中x表示i不在链上的儿子,y表示i在链上的儿子.

然后在各种用树状数组维护,具体我也不太清楚,因为不大会这道题.

题目代码也写不出来...

所以这里就不发代码啦.

猜你喜欢

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