队内训练第三周

涉及的知识点

本周练习主要涉及字符串

已完成题目 CodeForce:219A、1462B、520A、1367A、978B、855A、1384A、785A、1473B;POJ:1035、1936、2513、3349、2503

未完成题目 CodeForce:1451B、1478B、1476D、1478A;POJ:3080、3274、2151、1840、2002

已完成题目整理

CodeForce 219A

题目大意:给出一个数k,再给出一个字符串,判断该字符串能否通过k个相同的字符串来组成

思路:判断每种字符能否整除k即可

代码

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;
int k;
char str[1212];
int alpha[26],len;
int main()
{
    scanf("%d",&k);
    getchar();
    scanf("%s",str);
    len=strlen(str);
    for(int i=0; i<len; i++)
        alpha[str[i]-'a']++;
    for(int i=0; i<26; i++)
        if(alpha[i]%k)
        {
            printf("-1\n");
            return 0;
        }
    for(int t=0; t<k; t++)
        for(int i=0; i<26; i++)
            for(int j=1; j<=alpha[i]/k; j++)
                printf("%c",'a'+i);
    putchar('\n');
    return 0;
}

CodeForce 520A

题目大意:判断给出的字符串是否包括所有的26个字母

思路:略

代码

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
using namespace std;
int n;
bool alphabet[26];
char ch;
int main()
{
    scanf("%d",&n);
    getchar();
    while(n--)
    {
        ch=getchar();
        alphabet[(ch=tolower(ch))-'a']=true;
    }
    for(int i=0; i<26; i++)
        if(!alphabet[i])
        {
            printf("NO");
            return 0;
        }
    printf("YES");
    return 0;
}

CodeForce 1367A

题目大意:给出一个字符串,它由多个只用两个字母的字符串合成而来,如abac分解成ab、ba、ac后合成abbaac,求输入字符串的初始形式

思路:直接去掉特定位置字符即可

代码

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;
int t;
int main()
{
    cin >>t;
    while(t--)
    {
        char s[101]= {'\0'};
        cin >>s;
        int len=strlen(s);
        if(len==2)
        {
            cout <<s<<endl;
            continue;
        }
        for(int i=1; i<len; i+=2)
            if(i!=len-1)
                s[i]='\0';
        for(int i=0; i<len; i++)
            if(s[i])
                cout <<s[i];
        cout <<endl;
    }
    return 0;
}

CodeForce 978B

题目大意:给出一个字符串,不允许出现多于3个x相连,如果出现,判断删除多少个字符能满足条件

思路:直接模拟即可

代码

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
using namespace std;
int n,op,ans;
char ch;
int main()
{
    scanf("%d",&n);
    getchar();
    while(n--)
    {
        scanf("%c",&ch);
        if(ch=='x')
            ans++;
        else
            ans=0;
        if(ans==3)
        {
            op++;
            ans--;
        }
    }
    printf("%d",op);
    return 0;
}

CodeForce 855A

题目大意:给出一系列名字,判断后输入的是否先前已经出现

思路:直接使用unordered_map

代码

#include <iostream>
#include <cstring>
#include <unordered_map>
using namespace std;
unordered_map<string,bool>Names;
int n;
int main()
{
    cin >>n;
    while(n--)
    {
        string t;
        cin >>t;
        if(Names[t])
            cout <<"YES";
        else
            cout <<"NO";
        Names[t]=true;
        cout <<endl;
    }
    return 0;
}

CodeForces 1384A

题目大意:给出一个数n,再给出n个数,分别代表编号1与2,2与3…n-1与n间的公共前缀的长度,输出满足条件的n个字符串,结果有很多,只需输出任意一种

思路:多种结果,那么假设初始字符串均为’a’,根据数字来决定哪一位不同就变哪一位,变完之后直接输出即可,本题用char数组会出错

代码

    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    using namespace std;
    int t;
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            int n;
            scanf("%d",&n);
            string str(200,'a');
            cout <<str<<endl;
            while(n--)
            {
                int x;
                scanf("%d",&x);
                if(str[x]=='a')//如果初始为a则变为b,与原串在这一位不同,反之亦然
                    str[x]='b';
                else
                    str[x]='a';
                //str[x]=str[x]=='a'?'b':'a';
                cout <<str<<endl;
            }
        }
        return 0;
    }

CodeForce 785A

题目大意:对应字符串有对应值,求和

思路:略

代码

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
using namespace std;
int ans[26]={0,0,6,12,0,0,0,0,20,0,0,0,0,0,8,0,0,0,0,4,0,0,0,0,0,0},N,sum;
int main()
{
    scanf("%d",&N);
    getchar();
    while(N--)
    {
        char tmp[30];
        scanf("%s",tmp);
        getchar();
        sum+=ans[tmp[0]-'A'];
    }
    printf("%d",sum);
    return 0;
}

CodeForce 1473B

题目大意:定义最小公倍字符串,对于两个字符串,如果存在一个字符串可以由这两串复制自己构成,且该字符串在所有符合条件的串中长度最短,则这样的字符串为最小公倍字符串,现输入多组字符串,求其最小公倍字符串

思路:最小公倍字符串的长度必定小于等于两长度之积,因为如果最小公倍字符串存在,它的长度=A串重复单元个数×B串重复单元个数/个数的最大公因数,而重复单元个数一定小于等于本身长度,除以最大公因数后更是如此。又最小公倍字符一定是AB串中较小串长度的倍数,所以直接倍增较小串,判断在长度之积前倍增后的较小串能否“整除”较长串

代码

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
using namespace std;
int Q,len,lena,lenb;
string a,b,tmp;
bool flag;
bool Judge()
{
    if(len%lenb!=0) return false;
    for(int i=0; i<len; i++)
        if(tmp[i]!=b[i%lenb])
        {
            //cout <<tmp[i]<<" "<<b[i%lenb]<<endl;
            return false;
        }
    return true;
}
int main()
{
    scanf("%d",&Q);
    while(Q--)
    {
        tmp="";
        flag=false;
        len=0;
        cin >>a>>b;
        if(a.size()>b.size())
            swap(a,b);
        lena=a.length(),lenb=b.length();
        while(len<=lena*lenb)
        {
            tmp+=a;
            //cout <<tmp<<endl;
            len=tmp.length();
            if((flag=Judge())==true)
                break;
        }
        if(flag)
            cout <<tmp<<endl;
        else
            cout <<"-1"<<endl;
    }
    return 0;
}

POJ 1035

题目大意:先输入多个字符串作为词典,再输入多个字符串作为查询的单词,如果单词属于字典,则输出正确信息,如果不属于,则判断修改一位或删除一位或插入一位是否能变成属于字典的单词,按照能构成单词的顺序输出

思路:模拟该过程即可,暴力枚举,为了确保输出顺序,将字典中的每一个单词与输入的单词进行长度比较,如果前者等于后者,尝试修改,刚好多1,尝试插入,刚好少1,尝试删除

代码

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef struct letter
{
    int len;
    char s[17];
} let;
let str[10017];

void Repl(char *s, char *ss)
{
    int len = strlen(s),flag = 0,i = 0, j = 0;
    while(i < len)
    {
        if(flag >= 2)
            break;
        if(s[i++] != ss[j++])
            flag++;
    }
    if(flag < 2)
        printf(" %s",s);
}
void Inse(char *s, char *ss)
{
    int len = strlen(ss),flag = 0,i = 0, j = 0;
    while(j < len)
    {
        if(flag >= 2)
            break;
        if(s[i] == ss[j++])
            i++;
        else
            flag++;
    }
    if(flag < 2)
        printf(" %s",s);
}
void Dele(char *s, char *ss)
{
    int len = strlen(s),flag = 0,i = 0, j = 0;
    while(i < len)
    {
        if(flag >= 2)
            break;
        if(s[i++] == ss[j])
            j++;
        else
            flag++;
    }
    if(flag < 2)
        printf(" %s",s);
}
int main()
{
    char ss[17];
    int k = 0;
    while(scanf("%s",str[k].s)!=EOF)
    {
        str[k].len = strlen(str[k].s);
        if(str[k].s[0]=='#')
            break;
        k++;
    }
    while(scanf("%s",ss)!=EOF)
    {
        if(ss[0] == '#')
            break;
        int len = strlen(ss),flag = 0;
        for(int i = 0; i < k; i++)
        {
            if(!strcmp(ss,str[i].s))
            {
                printf("%s is correct\n",ss);
                flag = 1;
                break;
            }
        }
        if(flag)
            continue;
        printf("%s:",ss);
        for(int i = 0; i < k; i++)
        {
            if(len == str[i].len)
                Repl(str[i].s,ss);
            else if(len == str[i].len+1)
                Inse(str[i].s,ss);
            else if(len == str[i].len-1)
                Dele(str[i].s,ss);
        }
        printf("\n");
    }
    return 0;
}

POJ 1936

题目大意:给出两个字符串,判断前者是否为后者缩写

思路:以第一个字符串为基准找到第二个字符串与其对应元素相等的位置,在此基础上继续延伸

代码

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;
string s,t;
int main()
{
    while(cin >>s>>t)
    {
        int lens=s.length(),lent=t.length(),pos=-1;
        bool flag=false;
        for(int i=0; i<lens; i++)
        {
            for(int j=pos+1; j<lent; j++)
            {
                if(s[i]==t[j])
                {
                    flag=true;
                    pos=j;
                    break;
                }
            }
            if(flag&&i!=lens-1)
            {
                flag=false;
                continue;
            }
            else
                break;
        }
        if(flag)
            cout <<"Yes";
        else
            cout <<"No";
        cout <<endl;
    }
    return 0;
}

POJ 2513

题目大意:给出多根木棒,头和尾各有自己的颜色,只有颜色相同一端才能相连,且每次只能两根木棒相连,现在判断所有木棒能否连成一条直线

思路:判断欧拉回路(通过图中每条边且只通过一次,并且经过每一顶点),将输入的各颜色看成图上的节点,将字符串使用字典树哈希获得对应的编号,利用编号+并查集来判断图是否连通,再记录每个点的度,判断度为奇数的点是否为0个或3个

代码

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
using namespace std;
int degree[500001],pre[500001],ans;
struct Trie
{
    bool flag;
    int id;
    Trie*next[30];
    Trie()
    {
        flag=false;
        for(int i=0; i<30; i++)
            next[i]=0;
    }
} root;
int Hash(char*str)
{
    int len=strlen(str);
    Trie*t=&root;
    for(int i=0; i<len; i++)
    {
        int id=str[i]-'a';
        if(!t->next[id])
            t->next[id]=new Trie();
        t=t->next[id];
    }
    if(!t->flag)
    {
        t->flag=1;
        t->id=ans++;
    }
    return t->id;
}
int Seek(int x)
{
    if(pre[x]==x)return x;
    return pre[x]=Seek(pre[x]);
}
void Union(int x,int y)
{
    int fx=Seek(x),fy=Seek(y);
    if(fx!=fy)
        pre[fx]=fy;
}
int main()
{
    char s[20],t[20];
    for(int i=1; i<=500000; i++)
        pre[i]=i;
    while(~scanf("%s%s",s,t))
    {
        int x=Hash(s),y=Hash(t);
        Union(x,y);
        degree[x]++;
        degree[y]++;
    }
    ans--;
    int cnt=0,odd=0;
    for(int i=1; i<=ans; i++)
    {
        if(degree[i]%2==1)
            odd++;
        if(pre[i]==i)
            cnt++;
        if(cnt>=2||odd>=3)
        {
            cout<<"Impossible"<<endl;
            return 0;
        }
    }
    cout<<"Possible"<<endl;
    return 0;
}

POJ 3349

题目大意:给出多个雪花的6个角对应的角的个数,判断这些雪花中是否有顺时针看来相同或者逆时针看来相同的

思路:使用哈希的方法(求余)求取值,采用链地址法解决冲突,采用vector会超时,判断顺时针和逆时针相同分别判断A[i]==B[(i+j)%6](i为第i片雪花,j为B顺时针的偏移量)和A[i]==B[(5-i-j)%6]

代码

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
using namespace std;
int Prime = 999983,n,key;
int sum=0;
typedef struct node
{
    int data[6],next;
} node;
node e[100100];
node x;
int hash[999984];//哈希只存储相等值的遍历到的最后一个元素,每个雪花保存自己的下一个相同值雪花
bool flag = false,judge;
int main()
{
    scanf("%d",&n);
    memset(hash,-1,sizeof(hash));
    sum = 0;
    while(n--)
    {
        key = 0;
        for(int i=0; i<6; i++)
        {
            int t;
            scanf("%d",&t);
            key = ( key + t )%Prime;
            x.data[i] = t;
        }
        if(!flag)//如果没找到
        {
            for(int i=hash[key]; i!=-1; i=e[i].next)
            {
                node t=e[i];
                for(int j=0; j<6; j++)
                {
                    judge = true;
                    for(int k=0; k<6; k++)
                        if(t.data[k]!=x.data[(5-j-k+6)%6])
                        {
                            judge=false;
                            break;
                        }
                    if( judge )
                        flag = judge;
                }
                for(int j=0; j<6; j++)
                {
                    judge = true;
                    for(int k=0; k<6; k++)
                        if(t.data[k]!=x.data[(j+k)%6])
                        {
                            judge=false;
                            break;
                        }
                    if( judge )
                        flag = judge;
                }
            }
            sum++;//记下雪花个数
            e[ sum ] = x;//保存雪花数据
            e[ sum ].next = hash[key];//雪花的下一个被赋值为哈希表对应的头,尾插入,参考链地址法的插入
            hash[key] = sum;//当前雪花取代哈希链表头
        }
    }
    if(flag)
        cout<<"Twin snowflakes found."<<endl;
    else
        cout<<"No two snowflakes are alike."<<endl;
    return 0;
}

POJ 2503

题目大意:给出两个字符串,前者为后者的翻译,这样的字符串有多组,输入多组作为词典,之后再输出多个字符串,输出其翻译,如果不存在输出对应信息

思路:因为没有给出确切的字符串组数,所以只能一行行读,然后进行分割,之后用map存储且查找即可,map的find函数效率高于[]符号

代码

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <map>
using namespace std;
map<string,string>Dictionary;
map<string,string>::iterator p;
string output,input;
int main()
{
    string line="";
    while(1)
    {
        getline(cin,line);
        if(line=="")break;
        int pos=line.find(' ');
        output=line.substr(0,pos);
        input=line.substr(pos+1,line.rfind(' ')-pos-1);
        Dictionary[input]=output;
    }
    char word[300];
    while(scanf("%s",word)!=EOF)
    {
        if(Dictionary.find(word)!=Dictionary.end())
            cout <<Dictionary[word];
        else
            printf("eh");
        putchar('\n');
    }
    return 0;
}

总结

本周的题目较为基础,但是模拟赛的习题还是挺有难度,字符串部分需要整理好Weekly 5部分后加强练习

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值