Codeforces Round #634 (Div. 3) A-E2

地址:http://codeforces.com/contest/1335

    题意:将n分成a,b。保证a>b,问有几种分法

    解析:偶数输出n/2-1,奇数n/2即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
typedef long long ll;    
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        ll n;
        cin>>n;
        if(n%2==0)
            cout<<n/2-1<<endl;
        else
            cout<<n/2<<endl;
    }
}

     题意:输出一个长为n的字符串,要求a长度里有b个不同字母

     解析:其实弄来弄去还是只看一个len=a的串即可,比如abcabc,a=3, 从i=1到i=3和从i=2到i=4其实是同一个串而已,只是顺序不同罢了。所以根据要求构造成一个len=a,含有b个不同字符的串,然后把这个串依次往后接即可。自己写的有点麻烦......

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
typedef long long ll;    
char ch[2005],s[2005];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,a,b;
        cin>>n>>a>>b;
        if(a==b)
        {
            int k=0;
            for(int i=0;i<n;i++)
            {
                char mid=(char)(k+'a');
                k++;
                if(k==26)
                    k=0;
                cout<<mid;
            }
            cout<<endl;
        }
        else
        {
            int k=0;
            int cnt=0;
            int mid;
            char md;
            for(int i=0;i<a;i++)
            {
                ch[i]=(char)(k+'a');
                cnt++;
                if(cnt==b)
                {
                    mid=i;
                    md=ch[i];
                    break;
                }                
                k++;
            }
            for(int i=mid+1;i<a;i++)
                ch[i]=md;
            int tot=0;
            for(int i=0;i<n;i++)
            {
                cout<<ch[tot];
                tot++;
                if(tot==a-1)
                    tot=0;
            }
            cout<<endl;
        }
    }
}

     题意:在一个数组中挑些数分成两组,一组各不相等,一组全相等。

     解析:先统计出两个值,cnt:有多少种数。maxx:出现次数最多的数。然后把cnt--,这个cnt就是除了maxx以外有多少种数了。

        然后分情况:1:cnt==maxx,没得说,直接输出cnt

              2:maxx<cnt。没法进行补救,一组全相等我最大也就分出maxx,没法进行补救措施。这里给出样例:2 2 2 3 3 4 7 8 9供测试证明。

              3:maxx>cnt。是有可能进行补救的。因为cnt是不包含maxx的,所以可以从maxx挪出来一个放入cnt中,但是要保证两组的元素数目相同,所以要看看maxx-1和cnt+1的大小关系。如果cnt+1>maxx-1了,那肯定是不能往里补的,只能输出cnt。能补的话,就输出cnt+1。给出两个样例:1 2 4 4 4 4 3和2 2 2 2 2  7 4。这俩一个能补一个不能补,可以自行测试一下。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
int a[maxn];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        map<int,int>mp;
        int maxx=-1,cnt=0;
        for(int i=0;i<n;i++)
        {
            cin>>a[i];
            if(mp[a[i]]==0)
                cnt++;
            mp[a[i]]++;
            maxx=max(maxx,mp[a[i]]);
        }
        cnt--;
    //    cout<<cnt<<"--"<<maxx<<endl;
        if(maxx==cnt)
        {
            cout<<maxx<<endl;
            continue;
        }        
        else if(maxx<cnt)
        {
            cout<<maxx<<endl;
        }
        else
        {
            if(cnt+1>maxx-1)
                cout<<cnt<<endl;
            else
                cout<<cnt+1<<endl;
        }
    }
}

     题意:给你一个正确的9*9数独矩阵。对它改动不超过9次来实现每行每列每3*3都要有至少两个元素相同。

     解析:这个重在对题意的理解。可以看出,给出的一定是每行每列每3*3都没有重复元素的。所以要让它变成反数独矩阵,只需要任意找一个数x,把所有的x变成y(x!=y)就可以了。这样,保证了每行每列都有重复元素,而对于3*3,已知输入的3*3里一定没有重复元素,那么1-9都出现在了3*3里,我们把x变成y,一定会出现重复。

#include<bits/stdc++.h>
using namespace std;
const int maxn=10;
char s[maxn][maxn];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        for(int i=0;i<9;i++)
            cin>>s[i];
        for(int i=0;i<9;i++)
        {
            for(int j=0;j<9;j++)
            {
                if(s[i][j]=='3')
                    s[i][j]='4';
            }
        }
        for(int i=0;i<9;i++)
            cout<<s[i]<<endl;
    }
}

     题意:通过任意删除某些元素,来求出最大的aaa....bbb......aaaa(回文)的2x+y来。

     解析:这个题只要把方法想好,直接可以过E2的hard。

       在输入时,用vector来记录每个元素出现的位置。然后来枚举每一个出现次数>1的数,比如当前枚举的数字x的下标为 L1,L2,L3,R1,R2,R3。那么我们需要枚举L3-R1之间的数字,由于a<=26,所以用Num[26]来记录每个数字出现的次数,找出出现次数最多的数字mx,那么答案就更新为max(maxx,mx+2*mid)。这个mid=size/2,size为当前枚举的数字x出现了几次。这个操作,也许会通过一些样例,但还远远不够。

        for(int i=1;i<=26;i++)
        {
            int size=v[i].size(),mid;
            if(size==1)
                maxx=max(maxx,size);
            if(size<=1)
                continue;
            mid=size/2;
            int num[30]={0},mx=0;
            for(int j=v[i][mid-1]+1;j<v[i][size-mid];j++)
            {
                num[a[j]]++;
            }
            for(int j=1;j<=26;j++)
                mx=max(mx,num[j]);
            maxx=max(maxx,mx+mid*2);
        }

    其实这里也是两个贪心策略,len=2*x+y,x取最大是一个部分,y取最大又是一个部分,要想len最大,两个贪心都要弄一遍,才算完整。   

    给出样例1 2 2 1 2 2 1 2 2 1,根据上一段的做法,得的结果是6,而实际上是要把中间两个1去掉,答案为 1  2 2 2 2 2 2 1,len=8。因为上段的思想是:贪心,两侧数字的数目取最大。取的只是 1  1  2  2   1  1,这个len=6。当以2出现为两边时,中间两个2之间没有元素,为空,所以len=6。所以对于每次枚举的v[x][],还需要以中间向两边扩散,枚举中间空的其他元素出现次数Num[]

     第一次枚举1,1处,然后枚举2,2处.......v[x][]这个x的数目一直在减少,中间的数目一直在增加。注意这里的下标变化:

            for(int j=mid-1;j>0;j--)    //j即为当前一半的长度
            {
                for(int c=v[i][j-1]+1;c<v[i][j];c++)    //左
                    num[a[c]]++;
                for(int c=v[i][size-j-1]+1;c<v[i][size-j];c++)//右
                    num[a[c]]++;            
                for(int c=1;c<=26;c++)
                    mx=max(mx,num[c]);
                maxx=max(maxx,mx+j*2);    //更新最大值
            }
#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=2e3+10;
int a[maxn];
vector<int>v[30];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        for(int i=1;i<=26;i++)    //注意清空
            v[i].clear();
        cin>>n;
        for(int i=0;i<n;i++)
        {
            cin>>a[i];
            v[a[i]].push_back(i);
        }
        int maxx=-1;
        for(int i=1;i<=26;i++)  //枚举位于两侧的数字
        {
            int size=v[i].size(),mid;
            if(size==1)
                maxx=max(maxx,size);    //单种数字做为答案
            if(size<=1)
                continue;
            mid=size/2;    //一侧数量
            int num[30]={0},mx=0;
            for(int j=v[i][mid-1]+1;j<v[i][size-mid];j++)
            {
                num[a[j]]++;
            }
            for(int j=1;j<=26;j++)
                mx=max(mx,num[j]);
            maxx=max(maxx,mx+mid*2);//两侧取最大的贪心
            for(int j=mid-1;j>0;j--)
            {
                for(int c=v[i][j-1]+1;c<v[i][j];c++)    //左区间
                    num[a[c]]++;
                for(int c=v[i][size-j-1]+1;c<v[i][size-j];c++)    //右区间
                    num[a[c]]++;            
                for(int c=1;c<=26;c++)
                    mx=max(mx,num[c]);
                maxx=max(maxx,mx+j*2);//中间取最大的贪心
            }
        }
        cout<<maxx<<endl;
    }
}

    E2:

     题意:E2和E1的不同就是范围了。

     解析:直接用上面那套代码,范围改一下就可以了。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
int a[maxn];
vector<int>v[202];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        for(int i=1;i<=200;i++)
            v[i].clear();
        cin>>n;
        for(int i=0;i<n;i++)
        {
            cin>>a[i];
            v[a[i]].push_back(i);
        }
        int maxx=-1;
        for(int i=1;i<=200;i++)
        {
            int size=v[i].size(),mid;
            if(size==1)
                maxx=max(maxx,size);
            if(size<=1)
                continue;
            mid=size/2;
            int num[205]={0},mx=0;
            for(int j=v[i][mid-1]+1;j<v[i][size-mid];j++)
            {
                num[a[j]]++;
            }
            for(int j=1;j<=200;j++)
                mx=max(mx,num[j]);
            maxx=max(maxx,mx+mid*2);
            for(int j=mid-1;j>0;j--)
            {
                for(int c=v[i][j-1]+1;c<v[i][j];c++)
                    num[a[c]]++;
                for(int c=v[i][size-j-1]+1;c<v[i][size-j];c++)
                    num[a[c]]++;            
                for(int c=1;c<=200;c++)
                    mx=max(mx,num[c]);
                maxx=max(maxx,mx+j*2);
            }
        }
        cout<<maxx<<endl;
    }
}
posted @ 2020-04-14 20:03  liyexin  阅读(185)  评论(0编辑  收藏  举报