Educational Codeforces Round 50 (Rated for Div. 2) 全题解

版权声明:本文为博主原创文章,未经博主允许可以转载,但要注明出处 https://blog.csdn.net/wang3312362136/article/details/82622552

比赛链接

https://codeforces.com/contest/1036

A. Function Height

题目大意

n 个点, k 次操作,每次可以使一个点+1,求最终 n 个点的最大值。

1 n , k 10 18

题解

答案就是

k n

B. Diagonal Walking v.2

题目大意

q 次询问,每次要从 ( 0 , 0 ) 走到 ( n , m ) ,一个点可以走多次(包括起点和终点),一个点可以走一步到达周围的8个方向,如果是斜着走的一步就叫做“好的移动”,求 ( 0 , 0 ) 恰好走 k 步能不能 ( n , m ) 到达,如果不能输出-1,否则输出最多可以走多少次“好的移动”。

1 q 10 4 , 1 n , m , k 10 18

题解

-1的情况很好判断,就是max(n,m)>k

否则,如果 n + m k 不同奇偶,必须移动不好的一步来达到同奇偶,剩下的可以全部走斜的。

如果不能恰好走到,也就是 max ( n , m ) k 不同奇偶,那么必须做两次不好的移动使得恰好能走到 ( n , m )

C. Classy Numbers

题目大意

T 次询问,求区间 [ L i , R i ] 中有多少个非零数位 3 的数字。

1 T 10 4 , 1 L i , R i 10 18

题解

(伪)数位DP。对于区间 [ 1 , R ] ,拆成 [ 1 , a × 10 x 1 ] , [ a × 10 x , ( 10 a + b ) × 10 x 1 1 ] , [ ( 10 a + b ) × 10 x 1 , ( 100 a + 10 b + c ) × 10 x 2 1 ] , ,每段分别统计答案,每段的答案是很好统计的。

D. Vasya and Arrays

题目大意

有一种操作,将序列的任意一段用它们的和代替。现有两个序列 A , B ,可以执行任意次操作,问两个序列最终能否相同,若能,输出两个序列相同时最长的长度,不能输出-1。

1 | A | , | B | 3 × 10 5 , 1 A i , B i 10 9

题解

如果两个序列的和不同输出-1。

用两个值维护两个序列的前缀和,一个值大了就往另一个值加数,如果两个值相等答案+1。

E. Covered Points

题目大意

n 条线段,每条线段从 ( a i , b i ) ( c i , d i ) ,求至少被一条线段覆盖的整点个数。保证线段两两不在一条直线上。

1 n 10 3 , 10 6 a i , b i , c i , d i 10 6

题解

如果线段没有交点,那么每条线段对答案的贡献就是 gcd ( | c i a i | , | d i b i | )

如果没有3条线段共用一个交点,那么枚举每条线段的交点,如果是整点答案-1。

如果没有上面这些限制,我们可以开一个set,存每条线段与前面线段的交点,最后答案-set的大小。

F. Relatively Prime Powers

题目大意

一个数可以表示成 a 1 k 1 a 2 k 2 a n k n ,如果 gcd ( k 1 , k 2 , , k n ) = 1 ,就说这个数是好数。 T 组询问,求 [ 2 , M i ] 范围内的好数个数。

1 T 10 5 , 1 M i 10 18

题解

显然, [ 2 , N ] 范围内好数个数为

N 1 + i = 2 μ ( i ) × ( N 1 / i 1 )

但是如果直接这样算是 O ( T log 2 N )

考虑离线算法,按照询问降序排列。

对于每个询问,当 i = 2 时, n 很容易在 O ( log N ) 时间内得到,而 i 3 时, i = 3 N 1 / i 1 的值不超过 1.1 × 10 6 ,开一个数组记录 N 1 / i ,可以对于每个询问依次减到实际值。 μ ( i ) 可以预处理 O ( log N )

总的时间复杂度大概是 O ( T log N + 1.1 × 10 6 )

G. Sources and Sinks

题目大意

将没有入度的点称为源,将没有出度的点称为汇,一个点可以既是源又是汇。给一个 n 个点 m 条边的图,保证源和汇的个数相同且都 20 。现有一个算法:

  1. 找一个源和一个汇,可以相同。
  2. 连一条边从汇到源,如果这个图还有源和汇,进入1。

对于这个图,如果在1过程中,无论如何选取源和汇,最后得到的图都是强连通的,输出YES,否则输出NO

题解

设源和汇的个数都为 C

如果一个源集合 S 能够到达的所有汇为 T ,对于任意 S ,若 | S | 0 , | S | C , | S | | T | ,那么应该输出NO,因为如果 T 中每个点都与 S 中的点连边,那么 S 中的点就不能到达非 T 中的汇点。

现在我们用数学归纳法证明如果对于每个 S ,都有 | S | = 0 , | S | = C | S | < | T | ,那么应该输出YES

任取一个点 s

  1. s 一定能走到 s (显然)。
  2. s 能走到的汇的集合为 T ,如果 | T | = C ,那么证明了强连通;
  3. 否则,记 T 能走到的源为 S S 能走到的汇为 T ,由于 | T | = | S | < | T | ,因此每一次 | T | 的值都在变大,最终变成 | T | = C

因此只要 O ( C 2 C ) 的检查源的集合就可以判断了。

代码

A. Function Height

#include <cstdio>

long long a,b;

int main()
{
  scanf("%I64d%I64d",&a,&b);
  printf("%I64d\n",(b+a-1)/a);
  return 0;
}

B. Diagonal Walking v.2

#include <cstdio>
#include <algorithm>

int q;
long long n,m,k;

int main()
{
  scanf("%d",&q);
  while(q--)
    {
      scanf("%I64d%I64d%I64d",&n,&m,&k);
      if(n<m)
        {
          std::swap(n,m);
        }
      if(k<n)
        {
          puts("-1");
          continue;
        }
      if((n-m)&1)
        {
          --k;
        }
      else if((k-n)&1)
        {
          k-=2;
        }
      printf("%I64d\n",k);
    }
  return 0;
}

C. Classy Numbers

#include <cstdio>

const int pow[]={1,9,81,729};

int C(int a,int b)
{
  if(b>a)
    {
      return 0;
    }
  int res=1;
  for(int i=1; i<=b; ++i)
    {
      res=res*(a-i+1)/i;
    }
  return res;
}

int getval(long long x)
{
  int have=3,ans=0;
  long long bit=1;
  for(int i=1; i<=18; ++i)
    {
      bit*=10;
    }
  for(int i=18; i>=0; --i)
    {
      int v=x/bit;
      x%=bit;
      bit/=10;
      if(v==0)
        {
          continue;
        }
      for(int j=0; j<have; ++j)
        {
          ans+=v*C(i,j)*pow[j];
        }
      ans+=C(i,have)*pow[have];
      --have;
      if(have<0)
        {
          break;
        }
    }
  if(have>=0)
    {
      ++ans;
    }
  return ans;
}

int t;
long long a,b;

int main()
{
  scanf("%d",&t);
  while(t--)
    {
      scanf("%I64d%I64d",&a,&b);
      printf("%d\n",getval(b)-getval(a-1));
    }
  return 0;
}

D. Vasya and Arrays

#include <cstdio>

int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}

const int maxn=300000;

int n,m,a[maxn+10],b[maxn+10],ans;
long long suma,sumb;

int main()
{
  n=read();
  for(int i=1; i<=n; ++i)
    {
      a[i]=read();
      suma+=a[i];
    }
  m=read();
  for(int i=1; i<=m; ++i)
    {
      b[i]=read();
      sumb+=b[i];
    }
  if(suma!=sumb)
    {
      puts("-1");
      return 0;
    }
  suma=sumb=0;
  int l=1,r=1;
  while((l<=n)||(r<=m))
    {
      if(suma<=sumb)
        {
          suma+=a[l++];
        }
      else
        {
          sumb+=b[r++];
        }
      if(suma==sumb)
        {
          ++ans;
        }
    }
  printf("%d\n",ans);
  return 0;
}

E. Covered Points

#include <set>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <algorithm>

int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}

typedef std::pair<int,int> pii;

const int maxn=1000;
const double eps=0.00000001;

struct point
{
  double x,y;

  point(double _x=0,double _y=0):x(_x),y(_y){}
};

struct seg
{
  point l,r;

  seg(point _l=0,point _r=0):l(_l),r(_r){}
};

int n,ans;
seg s[maxn+10];
std::set<pii> t;

point getcp(seg a,seg b)
{
  double x1=a.l.x-a.r.x,x2=b.l.x-b.r.x,y1=a.l.y-a.r.y,y2=b.l.y-b.r.y;
  double bot=y1*x2-x1*y2;
  point ans(((b.r.y-a.r.y)*(x1*x2)+a.r.x*(y1*x2)-b.r.x*(x1*y2))/bot,
            ((a.r.x-b.r.x)*(y1*y2)+b.r.y*(y1*x2)-a.r.y*(x1*y2))/bot);
  return ans;
}

int gcd(int a,int b)
{
  return b?gcd(b,a%b):a;
}

int tr(double x)
{
  if(x>=0)
    {
      return (int)(x+0.5);
    }
  else
    {
      return (int)(x-0.5);
    }
}

int main()
{
  n=read();
  for(int i=1; i<=n; ++i)
    {
      int lx=read(),ly=read(),rx=read(),ry=read();
      s[i]=seg(point(lx,ly),point(rx,ry));
      int dx=abs(rx-lx),dy=abs(ry-ly);
      ans+=gcd(dx,dy)+1;
      t.clear();
      for(int j=1; j<i; ++j)
        {
          point cp=getcp(s[i],s[j]);
          int cpx=tr(cp.x),cpy=tr(cp.y);
          if((std::abs(cpx-cp.x)<eps)&&(std::abs(cpy-cp.y)<eps)
             &&(cpx>=std::min(lx,rx))&&(cpx>=std::min(s[j].l.x,s[j].r.x))
             &&(cpx<=std::max(lx,rx))&&(cpx<=std::max(s[j].l.x,s[j].r.x))
             &&(cpy>=std::min(ly,ry))&&(cpy>=std::min(s[j].l.y,s[j].r.y))
             &&(cpy<=std::max(ly,ry))&&(cpy<=std::max(s[j].l.y,s[j].r.y)))
            {
              t.insert(std::make_pair(cpx,cpy));
            }
        }
      ans-=t.size();
    }
  printf("%d\n",ans);
  return 0;
}

F. Relatively Prime Powers

#include <cmath>
#include <cstdio>
#include <algorithm>

const int maxk=65;
const int maxn=100000;
const double eps=0.000001;
const long long maxv=1000000000000000000ll;

struct query
{
  int id;
  long long val;

  bool operator <(const query &other) const
  {
    return val>other.val;
  }
};

int p[maxk+10],prime[maxk+10],mu[maxk+10],cnt,end[maxk+10],t;
long long ans[maxn+10];
query q[maxn+10];

int getmu()
{
  p[1]=1;
  mu[1]=1;
  for(int i=1; i<=maxk; ++i)
    {
      if(!p[i])
        {
          prime[++cnt]=i;
          mu[i]=-1;
        }
      for(int j=1; (j<=cnt)&&(i*prime[j]<=maxk); ++j)
        {
          p[i*prime[j]]=1;
          if(i%prime[j]==0)
            {
              mu[i*prime[j]]=0;
              break;
            }
          mu[i*prime[j]]=-mu[i];
        }
    }
  return 0;
}

long long spow(long long x,int b)
{
  long long res=1;
  while(b)
    {
      if(b&1)
        {
          res=res*x;
        }
      x=x*x;
      b>>=1;
    }
  return res;
}

long long check(long long x)
{
  end[2]=sqrt(x);
  for(int i=3; i<=maxk; ++i)
    {
      while(spow(end[i],i)>x)
        {
          --end[i];
        }
    }
  long long res=x-1;
  for(int i=2; i<=maxk; ++i)
    {
      res+=mu[i]*(end[i]-1);
    }
  return res;
}

int main()
{
  getmu();
  for(int i=3; i<=maxk; ++i)
    {
      end[i]=(long long)(pow(maxv,1.0/i)+eps);
    }
  scanf("%d",&t);
  for(int i=1; i<=t; ++i)
    {
      scanf("%I64d",&q[i].val);
      q[i].id=i;
    }
  std::sort(q+1,q+t+1);
  for(int i=1; i<=t; ++i)
    {
      ans[q[i].id]=check(q[i].val);
    }
  for(int i=1; i<=t; ++i)
    {
      printf("%I64d\n",ans[i]);
    }
  return 0;
}

G. Sources and Sinks

#include <cstdio>

int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}

const int maxn=1000000;
const int maxk=20;

int source[maxk+3],id[maxn+3],n,m,cnts,cntt;
int ru[maxn+10],chu[maxn+10],to[maxk+3];
int pre[maxn+10],now[maxn+10],son[maxn+10],tot;

int ins(int a,int b)
{
  pre[++tot]=now[a];
  now[a]=tot;
  son[tot]=b;
  return 0;
}

int search(int u,int st)
{
  if(id[u])
    {
      to[st]|=1<<(id[u]-1);
    }
  int j=now[u];
  while(j)
    {
      int v=son[j];
      search(v,st);
      j=pre[j];
    }
  return 0;
}

int main()
{
  n=read();
  m=read();
  for(int i=1; i<=m; ++i)
    {
      int a=read(),b=read();
      ins(a,b);
      ++chu[a];
      ++ru[b];
    }
  for(int i=1; i<=n; ++i)
    {
      if(!ru[i])
        {
          source[++cnts]=i;
        }
      if(!chu[i])
        {
          id[i]=++cntt;
        }
    }
  for(int i=1; i<=cnts; ++i)
    {
      search(source[i],i);
    }
  int flag=0;
  for(int sta=1; sta<(1<<cnts)-1; ++sta)
    {
      int ttot=0,scnt=0,cnt=0;
      for(int i=1; i<=cnts; ++i)
        {
          if(sta&(1<<(i-1)))
            {
              ++scnt;
              ttot|=to[i];
            }
        }
      for(int i=1; i<=cnts; ++i)
        {
          if(ttot&(1<<(i-1)))
            {
              ++cnt;
            }
        }
      if(cnt<=scnt)
        {
          flag=1;
          break;
        }
    }
  puts(flag?"NO":"YES");
  return 0;
}

猜你喜欢

转载自blog.csdn.net/wang3312362136/article/details/82622552