zoukankan      html  css  js  c++  java
  • Codeforces Round #565 (Div. 3)

    传送门

    A. Divide it!

    •题意

    给定一个数n, 每次可以进行下列一种操作

    1.如果n可以被2整除,用n/2代替n

    2.如果n可以被3整除,用2n/3代替n

    3.如果n可以被5整除,用4n/5代替n

    如果可以经过上述操作使得 n 变为 1,输出最小操作次数,反之,输出-1;

    •思路

    n/2 < 2n/3 < 4n/5 要想操作次数最少,优先操作 1 > 2 > 3;

    •代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    int a[105];
    int main()
    {
        int t;
        cin>>t;
        while(t--)
        {
            ll n;
            cin>>n;
            int flag=0;
            int Count=0;
            while(n>1)
            {
                if(n%2==0)//1
                {
                    n/=2;
                    Count++;
                }
                else if(n%3==0)//2
                {
                    n=n/3*2;
                    Count++;
                }
                else if(n%5==0)//3
                {
                    n=n/5*4;
                    Count++;
                }
                else//不能被整除,即经过操作不能变为1
                {
                    flag=1;
                    break;
                }
            }
            if(flag)
                cout<<-1<<endl;
            else
                cout<<Count<<endl;
        }
    }
    View Code

    B. Merge it!

    •题意

    给你一个包含 n 个数的序列 a;

      定义序列 a 上的一个操作:合并任意两个元素;

      你可以对序列 a 执行上述操作任意次,求操作后的序列最多有多少元素可以被 3 整除;

    •思路

    对于任意一个数x

    1.如果x是3的倍数,x%3==0

    如果x不是3的倍数

    2.如果x+1是3的倍数,x%3==1,3*x%x==0

    3.如果x+2是3的倍数,x%3==2,3*x%x==0

    如果想尽可能多的是三的倍数:

    首先加x%3==0的x的个数,这样只使用一个数

    其次2和3相加正好是3的倍数,这样只使用两个数

    最后还剩下2或者3,则自身结合,这样是使用三个数

    •代码

    #include<bits/stdc++.h>
    using namespace std;
    int a[105];
    int main()
    {
        int t;
        cin>>t;
        while(t--)
        {
            int n;
            cin>>n;
            int zero=0,one=0,two=0;//分别记录x%3为0,1,2的个数
            for(int i=0;i<n;i++)
            {
                cin>>a[i];
                a[i]%=3;
                if(a[i]==0)
                    zero++;
                else if(a[i]==1)
                    one++;
                else
                    two++;
            }
    //        cout<<zero<<' '<<one<<' '<<two<<endl;
            if(one>=two)
                cout<<zero+two+(one-two)/3<<endl;
            else
                cout<<zero+one+(two-one)/3<<endl;
        }
    }
    View Code

    C. Lose it!

    题意

      给你一个包含 n 个整数的序列 a和good序列{4,8,15,16,23,42};

      在删去 x 个数后,使得序列 a 可以划分成 (n-x) / 6 个 "good" 序列;

      求 x 的最小值;

    题解

      求出序列 a 最多有多少个 "good" 序列(假设有 ans 个),需要删去的个数就是 n-6×ans;

    •代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=500005;
    
    vector<int> p[43];
    int s[maxn];
    int t[]={0,4,8,15,16,23,42};
    int ans=0;//一共有ans个good串
    int a[50];//记录使用后的每个字母的最后一个位置,即这个字母到达的最远的位置
              //后面再找这个字母时,从这个位置的下一个开始找,可以减少查找量
    int main()
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>s[i];
            p[s[i]].push_back(i);//预处理s串每个good数的位置
        }
        int cur=0;
        int flag;
        for(int i=1;i<=6;i++)
        {
            flag=0;
            for(int j=a[t[i]];j<p[t[i]].size();j++)
            {
                flag=0;
                if(p[t[i]][j]>cur)//在s串中找x出现的位置 >cur 的第一个位置,有点贪心的感jio
                {
                    cur=p[t[i]][j];//更新cur
                    a[t[i]]=j+1;//记录之前x到达的最远位置j,后面从j+1开始找
                    flag=1;
                    break;
                }
            }
            if(!flag)
                break;
            if(cur>n)
                break;
            if(i==6)//找完一次,再从第一个good数找下一次
            {
                ans++;
                cur=0;
                i=0;
            }
        }
        cout<<n-ans*6<<endl;
    }
    View Code

    D. Recover it!

    •题意

    有一个数组a和一个数组b,其中b是这样组成的

    ①b中包含a中所有的数

    ②对于a中的数,如果ai是素数,那么在b中添加第ai个素数

      如果ai是合数,那么在b中添加ai的最大约数(除ai外的)

    如果a中有n个数,那么b中包含如上的2*n个数

    现给出b中的所有数,求a中的所有数

    •思路

    对于b中的数 ,我们可以考虑从大到小排序,

    ①如果最大的这个数是合数的话,那么他一定是a中的数,因为在b中添加的是比ai

    小的最大约数
    ②如果是素数的话,那么他一定是被添加到b中的数,也就是一定不是a中的数,而他所对应的这个素数的位置才是a中的数

    •代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2e5+5;
    const int mm=2750131;
    
    int Mark[mm+10];
    int prime[maxn];
    
    int index;
    void Prime()
    {
        memset(Mark,0,sizeof(Mark));
        for(int i=2;index<=199999;i++)
        {
            if(Mark[i]==0)
                prime[index++]=i;
            for(int j=0;j<index&&prime[j]*i<=mm;j++)
            {
                Mark[i*prime[j]]=1;
                if(i%prime[j]==0)
                    break;
            }
        }
    }
    
    map<int,int> mp;//用map存便于找是减少数量
    int a[maxn],b[2*maxn];
    int main()
    {
        Prime();
        int n;
        cin>>n;
    
        for(int i=0;i<2*n;i++)
        {
            cin>>b[i];
            mp[b[i]]++;
        }
        int cur=0;
        sort(b,b+2*n);
        for(int i=2*n-1;i>=0;i--)
        {
            if(!mp[b[i]])
                continue;
            if(cur>n)
                break;
            if(Mark[b[i]])//合数
            {
                a[cur++]=b[i];//加到a数组中
                for(int j=2;;j++)//找最大的约数
                {
                    if(b[i]%j==0)
                    {
                        mp[b[i]/j]--;//删去这个约数
                        break;
                    }
                }
            }
            else//素数
            {
                int p=1+lower_bound(prime,prime+index,b[i])-prime;//这个素数的位置
                a[cur++]=p;//加到a数组中
                mp[p]--;//删去这个代表位置的素数
            }
            mp[b[i]]--;//删去已经找完的这个数
        }
        for(int i=0;i<n;i++)
            cout<<a[i]<<' ';
    }
    View Code

    用map存是从李先生那偷过来的(QWQ)


     

    E. Cover it!

    题意

    从含有 n 个点,m 条边的无向图中取出 x 个点,这 x 个点需满足:

      ① x ≤ n/2;

      ②剩余的点至少与这 x 个点中的一个点有连边;

      输出满足条件的这 x 个点;

    题解

    李先生说这是二部图裸题,据他说,突然想到我们老班离散课上讲的知识,可能是我没听讲???(还不是因为太菜惹

    找出集合 U 和集合 V,输出 |U| 和 |V| 中元素个数最少的集合;

    以任意一个点开始,加入把他涂成红色,那和他相连的点涂成绿色,和这个点相邻的量再涂成红色....以此

    就分成了两个集合,输出点数较少的那个集合

    •代码

    bfs涂色

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=200005;
    int x,y;
    int cntx,cnty;
    struct Edge
    {
        int u;
        int v;
        int nex;
    }edge[2*maxn];
    struct Data//涂色
    {
        int v;
        int col;
    };
    int head[maxn],vis[maxn],cnt;
    int a[maxn],b[maxn];//0:红色,b:绿色  a[]为0集合,b[]为1集合
    void add(int u,int v)
    {
        edge[++cnt].u=u;
        edge[cnt].v=v;
        edge[cnt].nex=head[u];
        head[u]=cnt;
    }
    queue<Data>q;
    void paint()
    {
        while(!q.empty())//bfs涂色
        {
            Data tmp=q.front();
            int u=tmp.v;//这个点涂色
            q.pop();
            for(int i=head[u];i;i=edge[i].nex)
            {
                int v=edge[i].v;
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(Data{v,!tmp.col});//和他相连的点涂相反的颜色
                    if(tmp.col)//分在两个集合里
                        a[++cntx]=v;
                    else
                        b[++cnty]=v;
                }
            }
        }
    }
    
    
    int main()
    {
        int t;
        cin>>t;
        while(t--)
        {
            int n,m;
            cin>>n>>m;
            for(int i=1;i<=n;i++)
                vis[i]=0,head[i]=0,a[i]=0,b[i]=0;
            cnt=0;
            cntx=0,cnty=0;
    
            for(int i=0;i<m;i++)
            {
                cin>>x>>y;
                add(x,y);
                add(y,x);
            }
    
            while(!q.empty())
                q.pop();
            q.push(Data{x,0});//以一个点开始
            a[++cntx]=x;
            vis[x]=1;
            paint();
    
            if(cntx<=n/2)
            {
                cout<<cntx<<endl;
                for(int i=1;i<=cntx;i++)
                    cout<<a[i]<<' ';
            }
            else
            {
                cout<<cnty<<endl;
                for(int i=1;i<=cnty;i++)
                    cout<<b[i]<<' ';
            }
            cout<<endl;
        }
    }
    View Code

    dfs涂色

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+5;
    struct Edge
    {
        int v;
        int nex;
    }edge[4*maxn];
    int head[maxn*2];
    int cnt;
    void add(int u,int v)
    {
         edge[++cnt]=Edge{v,head[u]};
         head[u]=cnt;
    }
    int col[maxn*2];//染色数组分为0,1两组代表红、绿
    
    void paint(int u,int flag)//dfs涂色
    {
        col[u]=flag;//u点染成flag色
        for(int i=head[u];i;i=edge[i].nex)//下一个未染色的点染成和他相反的颜色
        {
            int v=edge[i].v;
            if(col[v]==-1)
                paint(v,!flag);
        }
    }
    int main()
    {
        int t;
        cin>>t;
        while(t--)
        {
            cnt=0;
            int n,m;
            cin>>n>>m;
            for(int i=1;i<=n;i++)
                head[i]=0,col[i]=-1;
            int x,y;
            for(int i=0;i<m;i++)
            {
                cin>>x>>y;
                add(x,y);
                add(y,x);
            }
            paint(x,0);
            int ans=0;
            for(int i=1;i<=n;i++)
                if(col[i])
                    ans++;
            if(ans>n/2)
            {
                cout<<n-ans<<endl;
                for(int i=1;i<=n;i++)
                    if(!col[i])
                        cout<<i<<' ';
            }
            else
            {
                cout<<ans<<endl;
                for(int i=1;i<=n;i++)
                    if(col[i])
                        cout<<i<<' ';
            }
            cout<<endl;
        }
    }
    View Code

    ps.偷偷学了一下李先生的链式前向星加边,比我以前的方法省了好多代码^(*-.-*)^

  • 相关阅读:
    图像检索(image retrieval)- 11
    图像检索(image retrieval)- 10相关
    Mock.js简易教程,脱离后端独立开发,实现增删改查功能
    Azure Monitor (3) 对虚拟机磁盘设置自定义监控
    Azure Monitor (1) 概述
    Azure SQL Managed Instance (2) 备份SQL MI
    Azure Virtual Network (17) Private Link演示
    Azure Virtual Network (16) Private Link
    Azure Virtual Network (15) Service Endpoint演示
    Azure Virtual Network (14) Service Endpoint服务终结点
  • 原文地址:https://www.cnblogs.com/MMMinoz/p/11073577.html
Copyright © 2011-2022 走看看