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

  • 相关阅读:
    查看 并发请求数及其TCP连接状态【转】
    nohup使用(转)
    Linux下高cpu解决方案(转载)
    Java.lang.String 乱码反编译
    apache2.2 搭载本地中转服务器
    转:对于服务器AdminServer, 与计算机Machine-0相关联的节点管理器无法访问
    感兴趣的github项目
    .NET CORE学习
    使用hMailServer搭建邮件服务器
    记录Sqlserver2012附加Sqlserver2008的数据库出错的解决方案
  • 原文地址:https://www.cnblogs.com/MMMinoz/p/11073577.html
Copyright © 2011-2022 走看看