暑假集训小总结-----STL模板(vector,string,set,map)7.21

集训三天,因为前几天的内容十分简单,因此没有写博客。今天讲的是stl的几个模板应用感觉对于我来说难度挺大,于是写篇博客增加自己对内容的理解和记忆。下面将对今天的练习题进行解析;

B题

Ananagrams,来源于UVa156,如果有兴趣,可以看详述,这里只做大意讲述:输出一些单词,找出所有满足一下条件的单词

:该单词不能通过字母的重排,得到输入文本中的另外一个单词。在判断是否满足条件时,字母不分大小写,但在输出时应保留原输入,按字典序排序。

 

 

下面进行题目内容分析:

        首先是第一个功能:不能通过字母重排得到另一个文本单词,分析如何实现这个功能,来看一个单词如果经过重排后得到另外一个单词,那么这两个单词的构成一定是一样的,于是就得到,这个功能的实现可以通过map<string,int>来实现如果map[字符串]>1;则代表着这个单词存在了,且当下你正在输入的单词是之前某个单词的重排,于是进行下一个单词的判断

string out(const string &s)        //首先通过这个函数来把每一个输入的单词换成小写;
{
	string ans;
	ans = s;
	for (int i = 0; i < ans.size(); i++)      
	{
		//if(isalpha(s[i]))
		ans[i] = tolower(ans[i]);
	}
	sort(ans.begin(), ans.end());//通过sort的升序排列,使得重排的每一个单词的顺序变得一样;
	return	ans;//这个单词的判断顺序;
}

然后返回到字符串在保存在map中

while (cin >> s)
	{
		if (s[0] == '#') break;
		word.push_back(s);
		string re = out(s);
		if (!cnt.count(re)) cnt[re] = 0;
		cnt[re]++;
	}

再来看其他的功能,判断时不分大小写已经在第一个功能时实现了,直接将所以的输入的副本小写;

因为是副本,所以原来的字符串要保存在一个vector中也就是word数组;

然后就是把结果输出了,但是字符串在map中无法正常输出,所以用一个vector<string>ss来接数据

vector<string>ans;
	for (int i = 0; i < word.size(); i++)
	{
		if (cnt[out(word[i])] == 1) ans.push_back(word[i]);
	}
	sort(ans.begin(), ans.end());

最后是输出

for (int i = 0; i < ans.size(); i++)
	{
		cout << ans[i] << endl;
	}

最后附上完整的AC代码

#include<bits/stdc++.h>
using namespace std;
vector<string>word;
map<string, int>cnt;
string out(const string &s)
{
	string ans;
	ans = s;
	for (int i = 0; i < ans.size(); i++)
	{
		//if(isalpha(s[i]))
		ans[i] = tolower(ans[i]);
	}
	sort(ans.begin(), ans.end());
	return	ans;
}
int main()
{
	string s;
	//int n;
	while (cin >> s)
	{
		if (s[0] == '#') break;
		word.push_back(s);
		string re = out(s);
		if (!cnt.count(re)) cnt[re] = 0;
		cnt[re]++;
	}
	vector<string>ans;
	for (int i = 0; i < word.size(); i++)
	{
		if (cnt[out(word[i])] == 1) ans.push_back(word[i]);
	}
	sort(ans.begin(), ans.end());
	for (int i = 0; i < ans.size(); i++)
	{
		cout << ans[i] << endl;
	}
	return	0;
}

C题 太简单,直接贴代码

#include<iostream>        //其实就是考了一个set是无重复的,如果你输入的那个数,之前已经有了,也
#include<stdio.h>          //也只有一个,在初始位置;
#include<set>
#include<algorithm>
using namespace std;
set<int>haha;
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=0;i<n;i++)
        {
            int x;
            scanf("%d",&x);
            haha.insert(x);
        }
        for(int i=0;i<m;i++)
        {
            int x;
            scanf("%d",&x);
            haha.insert(x);
        }
       // set<int>::iterator it
        int flag=0;
        for(set<int>::iterator it=haha.begin();it!=haha.end();it++)
        {
            if(flag==0)
            {
                cout<<*it;
                flag=1;
            }
            //cout<<*it;
            else if(flag==1)
            {
                cout<<" "<<*it;
            }
        }
        haha.clear();
        cout<<"\n";
    }
    return  0;
}

 

D题

     题目:夏天来了~~好开心啊,呵呵,好多好多水果~~
Joe经营着一个不大的水果店.他认为生存之道就是经营最受顾客欢迎的水果.现在他想要一份水果销售情况的明细表,这样Joe就可以很容易掌握所有水果的销售情况了.

输入:

         第一行正整数N(0<N<=10)表示有N组测试数据.
每组测试数据的第一行是一个整数M(0<M<=100),表示工有M次成功的交易.其后有M行数据,每行表示一次交易,由水果名称(小写字母组成,长度不超过80),水果产地(小写字母组成,长度不超过80)和交易的水果数目(正整数,不超过100)组成.

输出:

对于每一组测试数据,请你输出一份排版格式正确(请分析样本输出)的水果销售情况明细表.这份明细表包括所有水果的产地,名称和销售数目的信息.水果先按产地分类,产地按字母顺序排列;同一产地的水果按照名称排序,名称按字母顺序排序.
两组测试数据之间有一个空行.最后一组测试数据之后没有空行.

测试数据

1 5 apple shandong 3 pineapple guangdong 1 sugarcane guangdong 1 pineapple guangdong 3 pineapple guangdong 1

输出

guangdong
   |----pineapple(5)
   |----sugarcane(1)
shandong
   |----apple(3)

这道题还是挺有看头的,坦然这道题我没做出来,最后是上网搜的题解,也正好学习了map的二维用法,弥补了上课听讲不认真的漏洞;

#include<iostream>
#include<map>
#include<stdio.h>	
#include<string>//在某些编译器上scanf是不能用iostream来完成的;
#include<algorithm>
using namespace std;
int main()
{
	int n;
	scanf("%d", &n);
	while (n--)
	{
		int sum;
		map<string, map<string, int> >oj;
		scanf("%d", &sum);
		while (sum--)
		{
			int num;
			string where, kind;       //kind储存水果种类,where储存产地,从而为
			cin >> kind >> where >> num;    //下面的map表示做准备
			oj[where][kind] += num;    //这一点是我所学习的一个地方,二维map的使用,因为定义的是<string,map<> >所以oj<where>所表示的是map<string,int>这一部分;
		}  //而oj<where][kind]所表示的则是这个产地的某种水果的数量;
		map<string, map<string, int> >::iterator it;
		for ( it = oj.begin(); it != oj.end(); it++)
		{
			cout << it->first << endl;//it表示迭代器,这点毋庸多言,it->first用来表示第一个键值,也就是where,it->second则表示的是map<string,int>
			for (map<string, int>::iterator it_1 = it->second.begin(); it_1 != it->second.end(); it_1++)
			{
				cout << "   |----" << it_1->first << "(" << it_1->second << ")" << endl;
			}
		}
		if (n != 0) cout << endl;
	}
	//system("pause");
	return	0;
}

 

再对重要知识点进行总结:

对于一个二维的map来说:map<string,map<string,int> >::inerator it表示的最外面一层的迭代器,map<string,int> >::inerator it_2

表示对是里面一层迭代器,两者之间的关系it_2==it->second;

另外对于输出第一个键值只许cout<<it->first<<endl;

E题,也没什么就是简单的map定义的oj

附代码

#include<iostream>
#include<string>
#include<set>
#include<map>
#include<stdio.h>
using namespace std;
map<string,int>oj;
int main()
{
    int n;
    while(scanf("%d",&n)&&n!=0)
    {
        int max=0;
        string t,c;
        for(int i=0;i<n;i++)
        {
            cin>>t;
            if(!oj.count(t))oj[t]=0;
            oj[t]++;
            if(max<oj[t])
            {
                max=oj[t];
                c=t;
            }
            t.clear();
        }
        cout<<c<<endl;
        t.clear();
        c.clear();
    }
    return  0;
}

 

F题

题目大意是:Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀).

输入:输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师交给Ignatius统计的单词,一个空行代表单词表的结束.第二部分是一连串的提问,每行一个提问,每个提问都是一个字符串.

注意:本题只有一组测试数据,处理到文件结束.

输出:对于每个提问,给出以该字符串为前缀的单词的数量.

数据:banana band bee absolute acm   

           ba b band abc

输出:2 3 1 0

学长代码:

#include<stdio.h>//学长的思路是,在存每一个单词时把单词的最后一位一次删除,然后保存状态,以便在后来查后缀时直接查找
#include<string.h>
#include<map>
#include<string>
using namespace std;
map<string,int>ma;
int main()
{
    char s[10];
    while(gets(s))
    {
        int x=strlen(s);
        if(x==0)
        break;
        for(int i=x-1;i>=0;i--)
        {
            ma[s]++;s[i]='\0';//这步就是从最后一位开始删除,然后用map保存状态计数;
        }
    }
        while(scanf("%s",s)!=EOF)
        {
            printf("%d\n",ma[s]);
        }
    
    return 0;
}

 

G题,难度不算大,主要是启发了我关于oj的输入输出的问题,对于一些问题,如果你认为自己可以在输入后就可以按正确答案的样例输出,那你就可以直接输出,无须顾虑是否形式整体相同;

题意:

给出N个数,要求把其中重复的去掉,只保留第一次出现的数。

例如,给出的数为1 2 18 3 3 19 2 3 6 5 4,其中2和3有重复,去除后的结果为1 2 18 3 19 6 5 4。

输入:

输入第一行为正整数T,表示有T组数据。

接下来每组数据包括两行,第一行为正整数N,表示有N个数。第二行为要去重的N个正整数。

输出:

对于每组数据,输出一行,为去重后剩下的数字,数字之间用一个空格隔开。

代码;

#include<stdio.h>
#include<set>
using namespace std;
set<int>s;
int main()
{
    int t;
    scanf("%d",&t);
        while(t--)
        {
            s.clear();//这点很重要,我就是因为没注意到这一点导致WA了好几次;
            int n,x;
            scanf("%d%d",&n,&x);
           /* if(s.count(x)==0)
            {
                printf("%d",x);
                s.insert(x);
            }*/
            s.insert(x);
            printf("%d",x);
            for(int i=1;i<n;i++)
            {
                scanf("%d",&x);//原理就是你每次输入一个数,我都可以通过set的.cout来判断在不在set里面,如果在,下一个,如果不在,先输出,在储存,这样就保证了按照输入的顺序来输出;
                if(s.count(x)==0)
                {
                    printf(" %d", x);
                    s.insert(x);
                }
            }
           // printf("\n");
           puts("");
        }
        return  0;
}

还有两题都不是太难,不写了,睡了;2018/7/22  0:18

--------------------------------------------------------------------------------------------------------------------------------------------------

该填的的坑还是要填

I题:来源hdu

题意:

You are given an array d1,d2,…,dnd1,d2,…,dn consisting of nn integer numbers.

Your task is to split this array into three parts (some of which may be empty) in such a way that each element of the array belongs to exactly one of the three parts, and each of the parts forms a consecutive contiguous subsegment (possibly, empty) of the original array.

Let the sum of elements of the first part be sum1sum1, the sum of elements of the second part be sum2sum2 and the sum of elements of the third part be sum3sum3. Among all possible ways to split the array you have to choose a way such that sum1=sum3sum1=sum3and sum1sum1 is maximum possible.

More formally, if the first part of the array contains aa elements, the second part of the array contains bb elements and the third part contains cc elements, then:

 

sum1=∑1≤i≤adi,sum1=∑1≤i≤adi,

sum2=∑a+1≤i≤a+bdi,sum2=∑a+1≤i≤a+bdi,

sum3=∑a+b+1≤i≤a+b+cdi.sum3=∑a+b+1≤i≤a+b+cdi.

The sum of an empty array is 00.

Your task is to find a way to split the array such that sum1=sum3sum1=sum3 and sum1sum1 is maximum possible

输入:

The first line of the input contains one integer nn (1≤n≤2⋅1051≤n≤2⋅105) — the number of elements in the array dd.

The second line of the input contains nn integers d1,d2,…,dnd1,d2,…,dn (1≤di≤1091≤di≤109) — the elements of the array dd.

输出:

Print a single integer — the maximum possible value of sum1sum1, considering that the condition sum1=sum3sum1=sum3 must be met.

Obviously, at least one valid way to split the array exists (use a=c=0a=c=0 and b=nb=n).

数据

Input

5
1 3 1 1 4

Output

5

Input

5
1 3 2 1 4

Output

4

Input

3
4 1 2

Output

0

思路概述:这道题我没有使用stl模板而是应用了一个lower——bound的函数,这个函数的作用是查找数组中不小于你要查找的数的第一个位置;

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e+5;
long long arr[maxn+2];
long long be[maxn+2],end[maxn+2];
int main()
{
    int n;
    scanf("%d",&n);

    for(int i=0;i<n;i++)
    {
        scanf("%d",&arr[i]);
        if(i==0)be[0]=arr[0];
        else if(i>0) be[i]=arr[i]+be[i-1];
    }
    end[n-1]=arr[n-1];
    for(int i=n-2;i>=0;i--)
    {
        end[i]=end[i+1]+arr[i];
    }
    //int flag=0;
    long long ans=0;
    for(int i=0;i<n;i++)
    {
        //int x;
       // x=end[i];倒累加和数组在i时的值,然后把这个值在正累加和上查找
        //long long ans;
        long long  pos=lower_bound(be,be+n,end[i])-be;//就是利用lower_bound函数来查找在正序递增的和数组中相对应的倒累加和数组的位置
        if(be[pos]==end[i]&&(pos<i))可以想到,只有当倒累加和的数组的i>pos位置时,才成立,因为pos是sum1的位置,i是sum3的位置;
        {
           ans=max(ans,be[pos]);
        }
    }
   // if(flag==0) cout<<"0"<<endl;
   cout<<ans<<endl;
    return  0;
}

 

写完收工,2018/7/22  8:39   计算机院楼611;

努力努力再努力。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值