zoukankan      html  css  js  c++  java
  • Codeforces Round #628 (Div. 2)

    A. EhAb AnD gCd

    题意:找两个数使得他们的gcd和lcm之和为x。

    思路:取1和x-1即可。

     1 #include<bits/stdc++.h>
     2 #define LL long long
     3 #define dl double
     4 void rd(int &x){
     5  x=0;int f=1;char ch=getchar();
     6  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     7  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
     8 }
     9 void lrd(LL &x){
    10  x=0;int f=1;char ch=getchar();
    11  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    12  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
    13 }
    14 const int INF=1e9;
    15 const LL LINF=1e18;
    16 using namespace std;
    17 int T;
    18 int x;
    19 int main(){
    20 // freopen("in.txt","r",stdin);
    21  rd(T);
    22  while(T--){
    23   rd(x);
    24   printf("%d %d
    ",1,x-1);
    25  }
    26  return 0;
    27 }
    28 /**/
    View Code

    B. CopyCopyCopyCopyCopy

    题意:给n(1e5)个数字的序列,将它们复制为n份首尾相接,问最长上升子序列是多少(严格上升)。

    思路:原序列有多少个不同的数字,最终答案就是多少。我们可以在每一份取一个值来使得其单调上升。并且由于是严格上升,最终答案也不可能超过不同数字的个数。

     1 #include<bits/stdc++.h>
     2 #define LL long long
     3 #define dl double
     4 void rd(int &x){
     5  x=0;int f=1;char ch=getchar();
     6  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     7  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
     8 }
     9 void lrd(LL &x){
    10  x=0;int f=1;char ch=getchar();
    11  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    12  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
    13 }
    14 const int INF=1e9;
    15 const LL LINF=1e18;
    16 const int N=1e5+10;
    17 using namespace std;
    18 int T;
    19 int n,a[N];
    20 set<int>S;
    21 int main(){
    22 // freopen("in.txt","r",stdin);
    23  rd(T);
    24  while(T--){
    25   S.clear();int ans=0;
    26   rd(n);for(int i=1;i<=n;i++){rd(a[i]);if(S.find(a[i])==S.end())ans++;S.insert(a[i]);}
    27   printf("%d
    ",ans);
    28  }
    29  return 0;
    30 }
    31 /**/
    View Code

    C. Ehab and Path-etic MEXs

    题意:n(1e5)个节点的树,将0~n-2赋值到每条边上,使得对于所有的u,v,MEX(u,v)的最大值最小。MEX(u,v)表示uv的简单路径上未出现的最小非负整数的值。

    思路:

    方案一:对于所有叶子节点所连边依次赋值0,1,2...其余的边任意赋值。我们可以发现,MEX(u,v)最大的uv一定都对应叶子节点,否则将其延伸至叶子节点MEX(u,v)一定不会变小。同时可以发现一条路径上最多只有两个叶子节点,也就是按按上述方式赋值,可以保证最终答案就是2。而答案永远不可能小于2,因为0和1对应的两条边总可以通过一种方式将它们连接起来。当然,2个节点的情况要注意特判。

    方案二:寻找一个度数大于等于三的节点(如果不存在这样的节点,那么就是一条链,答案一定为n-1),将它的三条边赋值0,1,2,其它的值任意取,最终答案也能保证是2。因为0,1,2永远不可能同时被取到。

     1 #include<bits/stdc++.h>
     2 #define LL long long
     3 #define dl double
     4 void rd(int &x){
     5  x=0;int f=1;char ch=getchar();
     6  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     7  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
     8 }
     9 void lrd(LL &x){
    10  x=0;int f=1;char ch=getchar();
    11  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    12  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
    13 }
    14 const int INF=1e9;
    15 const LL LINF=1e18;
    16 const int N=1e5+10;
    17 using namespace std;
    18 int n;
    19 int fi[N],nxt[N<<1],to[N<<1],cst[N],tot;
    20 void link(int x,int y){nxt[++tot]=fi[x];fi[x]=tot;to[tot]=y;}
    21 int in[N];
    22 int main(){
    23 // freopen("in.txt","r",stdin);
    24  rd(n);
    25  for(int i=1;i<n;i++){
    26   int x,y;rd(x);rd(y);
    27   link(x,y);link(y,x);
    28   in[x]++;in[y]++;
    29  }
    30  int now=0;
    31  for(int i=1;i<=n;i++){
    32   if(in[i] != 1)continue;
    33   if(!cst[(fi[i]+1)/2])cst[(fi[i]+1)/2]=++now;
    34  }
    35  for(int i=1;i<n;i++)if(!cst[i])cst[i]=++now;
    36  for(int i=1;i<n;i++)printf("%d
    ",cst[i]-1);
    37  return 0;
    38 }
    39 /**/
    View Code

    D. Ehab the Xorcist

    题意:找若干个数使得他们的和为v(0~1e18),异或和为u(0~1e18)。尽可能使得找到的数的个数最少,输出方案。不合法输出-1。

    思路:存在公式a+b=(a^b)+2*(a&b),所以v必定是大于等于u的,而且奇偶性必然相同。所以只需要考虑v>=u且u%2==v%2的情况,我们可以发现一定可以构造出一组长度为3的解,即u,(v-u)/2,(v-u)/2,那么最终的答案就有了一个上界3。0个是u=v=0的特殊情况对应答案,1是u=v的特殊答案。考虑什么时候可以出现2的情况,如果u& ((v-u)/2)=0的话,我们就可以将二者合并为一个数字,那么就会出现2的情况。再考虑是否存在其他2的情况。不妨令两个数为x,y,按位考虑,如果u的当前位为1,那么xy中当前位分别为1和0,谁是1谁是0并不会对二者之和造成影响,不会影响构造,不妨令x为1,y为0,在考虑完所有1对应位的构造之后,x=u,y=0。如果u的当前位为0,那么xy的当前位的值其实是固定的,同为1或者同为0,其实也就是由(v-u)/2的对应位所决定的,而这必须保证和1对应位不发生冲突,其实条件也就是u&((v-u)/2)=0。最终两个数可以有很多种组合,但是判断的条件都是一样的。

     1 #include<bits/stdc++.h>
     2 #define LL long long
     3 #define dl double
     4 void rd(int &x){
     5  x=0;int f=1;char ch=getchar();
     6  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     7  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
     8 }
     9 void lrd(LL &x){
    10  x=0;int f=1;char ch=getchar();
    11  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    12  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
    13 }
    14 const int INF=1e9;
    15 const LL LINF=1e18;
    16 const int N=2e7+10;
    17 using namespace std;
    18 LL u,v;
    19 int main(){
    20 // freopen("in.txt","r",stdin);
    21  lrd(u);lrd(v);
    22  if(v < u || v%2 != u%2)printf("-1
    ");
    23  else if(u==0 && v==0)printf("0
    ");
    24  else if(u == v)printf("1
    %lld
    ",u);
    25  else {
    26   LL ans[3];ans[0]=u;ans[1]=ans[2]=(v-u)/2;int cnt=3;
    27   if((ans[0] & ans[1]) == 0)ans[0]|=ans[1],cnt--;
    28   printf("%d
    ",cnt);for(int i=0;i<cnt;i++)printf("%lld ",ans[i]);puts("");
    29  }
    30  return 0;
    31 }
    32 /*a+b=(a^b)+2*(a&b)*/
    View Code

    反思:a+b=(a^b)+2*(a&b)。学会u,(v-u)/2,(v-u)/2这种构造思路,取两个相同的数字就改变和而不改变异或和。

    E. Ehab's REAL Number Theory Problem

    题意:给n(1e5)个数ai(1~1e6),每个数的约数不超过7个,要求选出最少的数使得他们的乘积是一个完全平方数,输出选择的个数即可,如果不存在合法方案输出-1。

    思路:我以为是dp之类的,然而不是。这是一道神奇的图论题。先看预处理过程。对于ai,我们将其中所包含的平方因子除去,对最终答案的选择不会有影响,并且约数个数不会增加,那么此时将其分解质因数后,每个质因数的个数至多为1个。如果是由3个质因子组成的,那么它有8个约数,所以ai至多由两个质因子组成,那么可以分为三种情况1,p,p*q,(p,q为素数)。如果存在1的情况,我们就可以直接找到完全平方数了,题目结束。所以只剩下p和p*q。我们不妨将p看成p*1。考虑ai=p*q,我们将ai和p,q两个因子分别连边得到一张图。可以发现乘积为完全平方数对应图上的一个环,要使选择的数个数最少,也就是要求选择的环最小。问题便转换为了寻找一张图上的最小环。无权值的情况下求最小环是可以在n^2的时间内做到的,即对于每个点bfs,一旦bfs到已访问过的点,这两个点到他们的lca便形成了一个环,而事实上我们直接假设lca是根来更新答案即可,因为如果不是的话并不会使得答案变得更小,并且后面会再次计算到这个环,因为对所有点都进行了bfs,所以总会对最小环上的点bfs,这时得到该环的两点的lca就是根了。需要注意这里不可以用dfs,因为dfs会由于加边顺序的不同找到的环也不同,找到的环可能不是最小的,具体情况可以看我代码中给出的注释。而如何将n^2优化,我们可以发现ai的上限是1e6,也就是一定存在一个<=1000的因子,所以所有的环上都包括1~1000的某个值对应的点,那么我们只需要对这些点进行bfs即可。

     1 #include<bits/stdc++.h>
     2 #define LL long long
     3 #define dl double
     4 void rd(int &x){
     5  x=0;int f=1;char ch=getchar();
     6  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     7  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
     8 }
     9 void lrd(LL &x){
    10  x=0;int f=1;char ch=getchar();
    11  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    12  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
    13 }
    14 const int INF=1e9;
    15 const LL LINF=1e18;
    16 const int N=1e5+10;
    17 using namespace std;
    18 int n;
    19 int b[N][2];
    20 int fi[N*11],to[N<<2],nxt[N<<2],tot;
    21 void link(int x,int y){nxt[++tot]=fi[x];fi[x]=tot;to[tot]=y;}
    22 int ans,dep[N*11];
    23 //dfs不能用,可能导致得到的环长度不是最短,比如1->2,2->3,3->4,4->5,3->5,5->1 
    24 void clear(int x){
    25  dep[x]=-1;
    26  for(int i=fi[x];i;i=nxt[i])
    27   if(dep[to[i]] != -1)clear(to[i]);
    28 }
    29 queue<pair<int,int> >S;
    30 void bfs(int x){
    31  clear(x);S.push(make_pair(x,0));dep[x]=0;
    32  while(!S.empty()){
    33   pair<int,int> u=S.front();S.pop();
    34   for(int i=fi[u.first];i;i=nxt[i])
    35    if(dep[to[i]] == -1){
    36     dep[to[i]]=dep[u.first]+(to[i]<=n);
    37     S.push(make_pair(to[i],u.first));
    38    }
    39    else if(to[i] != u.second)ans=min(ans,dep[u.first]+dep[to[i]]);
    40  }
    41 }
    42 int main(){
    43 // freopen("in.txt","r",stdin);
    44  rd(n);bool flg=0;
    45  for(int i=1;i<=n;i++){
    46   int x;rd(x);
    47   int tmp1=sqrt(x),tmp2=0;
    48   for(int j=2;j<=tmp1;j++){
    49    if(x % j)continue;int cnt=0;
    50    while(x % j ==0)x/=j,cnt++;
    51    if(cnt & 1)b[i][tmp2++]=j;
    52   }
    53   if(x != 1)b[i][tmp2++]=x;
    54   if(tmp2 == 0){flg=1;break;}
    55   if(tmp2 == 1)b[i][tmp2]=1;
    56   link(i,n+b[i][0]);link(n+b[i][0],i);
    57   link(i,n+b[i][1]);link(n+b[i][1],i);
    58  }
    59  if(flg)printf("1
    ");
    60  else {
    61   ans=0x7fffffff;
    62   for(int i=n+1;i<=n+1000;i++)if(fi[i])bfs(i);
    63   if(ans == 0x7fffffff)ans=-1;
    64   printf("%d
    ",ans);
    65  }
    66  return 0;
    67 }
    View Code

    F. Ehab's Last Theorem

    题意:n(1e5)个点m(2e5)条边的图,设sq=根号n上取整,找到一个大小为sq的独立子集或者找到一个长度大于等于sq的简单环,输出方案,题目保证至少有一个可以求出来。

    思路:考虑dfs树的做法来求最大环。任找一个点dfs,搜到已访问的点就出现了环,判断环的大小是否大于等于sq,虽然不能找到所有的环,但能找到所有比较大的环。有关dfs树的知识可以看官方题解给的blog,写的相当好。如果最后都没能找到大于等于sq的环,那么必然不存在两个相连的点深度差大于等于sq-1的(dfs树上的非树边一定是连接了祖先和儿子),那么对于所有的点按它们的深度%(sq-1)分类,必然存在至少一种,它包含了至少sq个互不相连的点(抽屉原理),从中取sq个即可。

     1 #include<bits/stdc++.h>
     2 #define LL long long
     3 #define dl double
     4 void rd(int &x){
     5  x=0;int f=1;char ch=getchar();
     6  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     7  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
     8 }
     9 void lrd(LL &x){
    10  x=0;int f=1;char ch=getchar();
    11  while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    12  while(ch<='9' && ch>='0')x=x*10+ch-'0',ch=getchar();x*=f;
    13 }
    14 const int INF=1e9;
    15 const LL LINF=1e18;
    16 const int N=1e5+10;
    17 using namespace std;
    18 int n,m;
    19 int fi[N],nxt[N<<2],to[N<<2],tot;
    20 void link(int x,int y){nxt[++tot]=fi[x];fi[x]=tot;to[tot]=y;}
    21 int dep[N],sq,fa[N];
    22 vector<int>S[N];
    23 void dfs(int x){
    24  dep[x]=dep[fa[x]]+1;S[dep[x]%(sq-1)].push_back(x);
    25  for(int i=fi[x];i;i=nxt[i]){
    26   if(!dep[to[i]])fa[to[i]]=x,dfs(to[i]);
    27   else if(dep[x]-dep[to[i]]+1 >= sq){
    28    printf("%d
    %d
    ",2,dep[x]-dep[to[i]]+1);
    29    while(x != to[i])printf("%d ",x),x=fa[x];
    30    printf("%d
    ",x);
    31    exit(0);
    32   }
    33  }
    34 }
    35 int main(){
    36 // freopen("in.txt","r",stdin);
    37  rd(n);rd(m);
    38  sq=sqrt(n);if(sq*sq < n)sq++;
    39  for(int i=1;i<=m;i++){
    40   int x,y;rd(x);rd(y);
    41   link(x,y);link(y,x);
    42  }
    43  dfs(1);printf("%d
    ",1);
    44  for(int i=0;i<sq-1;i++)
    45   if(S[i].size() >= sq){
    46    for(int j=0;j<sq;j++)
    47     printf("%d ",S[i][j]);
    48    break;
    49   }
    50  puts("");
    51  return 0;
    52 }
    53 /**/
    View Code

    反思:学会dfs树找环。特殊情况求独立子集不是np问题。

  • 相关阅读:
    第二次Soring冲刺计划第四天(团队)
    第二次Soring冲刺计划第四天(个人)
    第二次Soring冲刺计划第三天(团队)
    第二次Soring冲刺计划第三天(个人)
    第二次Soring冲刺计划第二天(团队)
    第二次Soring冲刺计划第二天(个人)
    第二次Soring冲刺计划第一天(个人)
    2018.12.6
    2108.12.5
    2018.12.4
  • 原文地址:https://www.cnblogs.com/hyghb/p/12507166.html
Copyright © 2011-2022 走看看