2011.网研院.Problem A.字符串操作
链接1: http://10.105.242.83/problem/140 链接2: http://10.105.242.80/problem/p/107
Description
大家平时都会用到字符串,现在有几种字符串操作,需要你用这几种操作处理下字符串。
Input
多组数据,以EOF结束。
第一行一个字符串,字符串长度大于0,并且小于等于200。
第二行一个数字t,(0<t<=200)。
下面t行,每行表示一种操作。
共有两种操作,每行数据的第一个数表示操作的种类:
翻转操作:第一个是一个数字0,然后两个数字i和len,翻转从下标i长度为len的子串。
替换操作:第一个是一个数字1,然后两个数字i和len,接着一个长度为len的字符串str,用str替换从下标i长度为len的子串。
字符串操作后会更新,旧的字符串被舍弃。(详见sample)
Output
每个操作之后输出生成的新的字符串
Sample Input
bac
2
0 0 3
1 1 2 as
Sample Output
cab
cas
Hint
字符串下标从0开始,所有操作的数据范围都合乎规范。
代码
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
string str;
int n;
int num1, num2, num3;
string str2;
while(cin >> str)
{
cin >> n;
while( n-- )
{
cin >> num1 >> num2 >> num3;
if( num1 == 0 )
reverse( str.begin()+ num2, str.begin()+num2+num3 );
else
{
cin >> str2;
str.erase( num2, num3 );
str.insert( num2, str2 );
}
cout << str << endl;
}
}
return 0;
}
2011.网研院.Problem B.虚数
链接1: http://10.105.242.83/problem/141 链接2: http://10.105.242.80/problem/p/108
链接3: 牛客网 - 虚数
Description
给你一个复数集合{Aj+i*Bj},保证Aj和Bj都是整数,初始为空集。
每次会给你如下两种操作中的一种:
1.“Insert x+iy”,其中x,y都是整数。表示在集合中加入一个复数 x+iy,同时输出此时集合的大小;
2.“Pop”。如果集合为空集直接返回“Empty!”,如果有元素则以"x+iy"的形式显示集合中模值最大的复数,然后将该元素从集合中删除,之后在第二行显示操作之后的集合大小,如果为空集则显示“Empty!”。
Input
第一行只有一个数T,代表case数。0<=T<=10
每一组case:
第一行有一个整数n,表示这组case中一共有n条命令 0<n<=100
接下来n行每行有一个命令,命令如上所述
保证不会输入两个模值同样的元素,并保证实部虚部都大于0,小于1000。
Output
依照上述原则输出每一个命令对应的输出
如果输入命令是Insert命令,则对应的输出占一行为集合大小;
如果输入命令是Pop命令,则对应的输出占一行或者两行,为模值最大的复数和集合大小。
请注意,输出集合大小的格式为"Size:空格x回车",x为集合大小
Sample Input
1
5
Pop
Insert 1+i2
Insert 2+i3
Pop
Pop
Sample Output
Empty!
Size: 1
Size: 2
2+i3
Size: 1
1+i2
Empty!
代码
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#include <cmath>
using namespace std;
struct complex
{
int real;
int imaginary;
double module;
friend bool operator < ( complex a, complex b )
{
return a.module < b.module;
}
};
int main()
{
int T, n;
scanf( "%d", &T );
char demand[8];
priority_queue<complex> cset;
complex temp;
while( T-- )
{
while( cset.size() )
cset.pop();
scanf("%d", &n);
while( n-- )
{
scanf("%s", demand);
if( !strcmp(demand, "Insert") )
{
scanf("%d+i%d", &temp.real, &temp.imaginary );
temp.module = sqrt(1.0*temp.real*temp.real + temp.imaginary*temp.imaginary );
cset.push( temp );
printf("Size: %d\n", cset.size());
}
else if( !strcmp(demand, "Pop") )
{
if( !cset.size() )
printf("Empty!\n");
else
{
temp = cset.top();
cset.pop();
printf("%d+i%d\n", temp.real, temp.imaginary );
if( !cset.size() )
printf("Empty!\n");
else
printf("Size: %d\n", cset.size());
}
}
}
}
return 0;
}
2011.网研院.Problem C.中序遍历树
链接1: http://10.105.242.83/problem/142 链接2: http://10.105.242.80/problem/p/109
Description
给一棵树,你可以把其中任意一个节点作为根节点。每个节点都有一个小写字母,中序遍历,得到一个字符串,求所有能得到的字符串的字典序最小串。因为这棵树不一定是二叉树,所以中序遍历时,先中序遍历以节点序号最小的节点为根的子树,然后再遍历根节点,最后根据节点序号从小到大依次中序遍历剩下的子树。
Input
多组数据,以EOF结束。
第一行一个数n(0<n<=100),表示树的节点的个数,节点从0开始。
然后一个长度为n的串,第i(0<=i<n)个字符表示节点i的字符。 接下来n-1行,每行两个数a,b,(0<=a,b<n),表示a和b之间有一条无向边。
Output
题中要求的最小的字符串
Sample Input
3
bac
0 1
1 2
4
abcd
0 1
0 2
0 3
Sample Output
bac
bacd
Hint
意思就是请枚举所有的点为根,然后中序遍历
最后输出所有结果中字典序最小的
比如说第二组数据
以0为根时结果为 bacd
以1为根时结果为 cadb
以2为根时结果为 badc
以3为根时结果为 bacd
所以字典序最小的是bacd
代码
#include <iostream>
#include <vector>
using namespace std;
const int maxsize = 26;
string data; //节点数据
string path;
string temp;
vector<int> vertex[maxsize];
int numNode = 0;
bool visit[maxsize] = {false};
void inorder( int root )
{
visit[root] = true;
int i;
for( i = 0; i < vertex[root].size(); i++ ) // 找到第一个未被标记的孩子 即为左子树 遍历玩此左子树 就推出循环
{
int lc = vertex[root][i];
if( !visit[lc] )
{
inorder( lc );
break;
}
}
temp.push_back( data[root] ); //访问根节点
int sonsize = vertex[root].size();
for( i = i+1; i < sonsize; i++ ) //上述 i 指向第一个左孩子 接下来依次遍历每个右孩子
{
int rc = vertex[root][i];
if( !visit[rc] )
inorder( rc );
}
}
int main()
{
while( cin >> numNode )
{
for( int i = 0; i < numNode; i++ )
vertex[i].clear();
data.clear();
temp.clear();
path.clear();
cin >> data;
int i, u, v;
for( i = 0; i < numNode-1; i++ )
{
cin >> u >> v;
vertex[u].push_back( v );
vertex[v].push_back( u );
}
for( int i = 0; i < numNode; i++ )
{
sort( vertex[i].begin(), vertex[i].end() );
}
memset( visit, false, maxsize );
inorder(0);
path = temp;
for( i = 1; i < numNode; i++ )
{
memset( visit, false, maxsize );
temp.clear();
inorder( i );
if( temp < path )
path = temp;
}
cout << path << endl;
}
return 0;
}
2011.网研院.Problem D.first集
链接1: http://10.105.242.83/problem/143 链接2: http://10.105.242.80/problem/p/110
Description
对于文法,给出求first集的算法,让大家求first集。输入中大写字母表示非终结符,小写字母表示终结符,#表示空也是终结符。
First集求解算法如下:
为了求每个符号的first集,连续使用以下规则,直到每个符号的first集不再增大为止。
1.对于终结符,它的first集就是它自己。
2.对于非终结符,如果有产生式 X -> a… ,把a加入first(X)中,
如果X-># ,即X可以推出空,那么把空加入first(X)中。
3.对于X->Y… 这样的产生式,且X,Y都是非终结符,把first(Y)中的所有非空的元素加入到first(X)中。
对于X->Y1Y2…Yk产生式,X,Y1,Y2…Yk都是非终结符,对于某个i(i<=k),如果first(Y1),first(Y2),…first(Yi-1) 都含有空,那么将first(Yi)中的所有非空元素加入到first(X)中。若所有的first(Yi)(i=1,2,…k)中都有空,那么将空加入first(X)中。
Input
多组数据,以EOF结束。
第一行一个数字n,表示有n个文法式,(0<n<=10)。
下面n行,每行第一个是一个大写字母,表示产生式的左边,然后一个字符串,由大写字母(非终结符),小写字母(终结符)和#(空)组成。
Output
按照字典序输出每个非终结符的first(集)。
每行表示一个first集。第一个字母输出表示非终结符(按字母序排列),然后按字母顺序输出first集,如果包含空的话,最后输出#。一行中每两个字符间有一个空格。
Sample Input
4
B A
A ab
A c
A #
Sample Output
A a c #
B a c #
Hint
思路
欣赏一下题目就行了,这题据说当年打比赛拿奖的出题人都未能在规定时间做出来,我等渣渣看看题目就好。