作业Week9、10+月模拟题3、4+CSP3、4+限时大模拟10、14

CSP3
A-瑞神的序列
1.题意:瑞神的数学一向是最好的,连强大的咕咕东都要拜倒在瑞神的数学水平之下,虽然咕咕东很苦 恼,但是咕咕东拿瑞神一点办法都没有。
  5.1期间大家都出去玩了,只有瑞神还在孜孜不倦的学习,瑞神想到了一个序列,这个序列长度为n,也就是一共有 个数,瑞神给自己出了一个问题:数列有几段?
  段的定义是连续的相同的最长整数序列
Input
输入第一行一个整数n,表示数的个数。
接下来一行n个空格隔开的整数,表示不同的数字

Output
输出一行,这个序列有多少段

Example
Input

12
2 3 3 6 6 6 1 1 4 5 1 4
1
2

Output
8

2.思路:该题较为简单,我们要做的操作就是判断前一个与后一个是否相同,如果不相同则最终结果ans加1.

3.代码:

#include 
using namespace std;

int main()
{
	int* a=new int[1001];
	int num, ans, n;
	cin>>n;
	num=1001,ans=0;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
		if(a[i]!=num)
		{
			num=a[i];
			ans++;
		}
	}
	cout<<ans<<endl;
	return 0;
}

B-消消乐大师-Q老师
1.题意:Q老师是个很老实的老师,最近在积极准备考研。Q老师平时只喜欢用Linux系统,所以Q老师的电 脑上没什么娱乐的游戏,所以Q老师平时除了玩Linux上的赛车游戏SuperTuxKart之外,就是喜欢 消消乐了。
  游戏在一个包含有n 行m 列的棋盘上进行,棋盘的每个格子都有一种颜色的棋子。当一行或一列 上有连续三个或更多的相同颜色的棋子时,这些棋子都被消除。当有多处可以被消除时,这些地 方的棋子将同时被消除。
  一个棋子可能在某一行和某一列同时被消除。 由于这个游戏是闯关制,而且有时间限制,当Q老师打开下一关时,Q老师的好哥们叫Q老师去爬 泰山去了,Q老师不想输在这一关,所以它来求助你了!!
Input
输入第一行包含两个整数n,m,表示行数和列数
接下来n行m列,每行中数字用空格隔开,每个数字代表这个位置的棋子的颜色。数字都大于0.
Output
输出n行m列,每行中数字用空格隔开,输出消除之后的棋盘。(如果一个方格中的棋子被消除, 则对应的方格输出0,否则输出棋子的颜色编号。
Example
Input
4 5
2 2 3 1 2
3 1 1 1 1
2 3 2 1 3
2 2 3 3 3
Output
2 2 3 0 2
3 0 0 0 0
2 3 2 0 3
2 2 0 0 0

2.思路:我们可以将输入的矩阵存成两个,之后分别判断两个矩阵中行和列是否存在可消除的元素,若存在,则将对应位置置为零。输出时,只要两个矩阵中有一个对应位置为0,就输出0,即可得到正确答案。

3.代码:

#include 
#include
using namespace std;

int a[100][100], b[100][100];

int main()
{
	int n, m, num, sum;
	cin>>n>>m;
	for(int i=0;i<n;i++)
		for(int j=0;j<m;j++)
		{
			cin>>a[i][j];
			b[i][j] = a[i][j];
		}
	for(int i=0;i<n;i++)
		for(int j=0;j<m-1;j++)
		{
			sum = 1;
			while(a[i][j]==a[i][j+1])
				sum++, j++; 
			if(sum>=3)
			{
				for(int temp = j;temp>j-sum;temp--)
					a[i][temp] = 0;
			}
		}
	for(int j=0;j<m;j++)
		for(int i=0;i<n-1;i++)
		{
			sum = 1;
			while(b[i][j]==b[i+1][j])
				sum++, i++; 
			if(sum>=3)
			{
				for(int temp = i;temp>i-sum;temp--)
					b[temp][j] = 0;
			}
		}
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<m;j++)
		{
			if(a[i][j]!=0&&b[i][j]!=0)
				cout<<a[i][j];
			else
				cout<<0;
			if(j!=m-1)
				cout<<" ";
		}
		if(i!=n-1)
			cout<<endl;
	}
	return 0;
}

C-咕咕东学英语
1.题意:咕咕东很聪明,但他最近不幸被来自宇宙的宇宙射线击中,遭到了降智打击,他的英语水平被归零了!这一切的始作俑者宇宙狗却毫不知情!
  此时咕咕东碰到了一个好心人——TT,TT在吸猫之余教咕咕东学英语。今天TT打算教咕咕东字母A 和字母B,TT给了咕咕东一个只有大写A、B组成的序列,让咕咕东分辨这些字母。
  但是咕咕东的其他学科水平都还在,敏锐的咕咕东想出一个问题考考TT:咕咕东问TT这个字符串 有多少个子串是Delicious的。
  TT虽然会做这个问题,但是他吸完猫发现辉夜大小姐更新了,不想回答这个问题,并抛给了你, 你能帮他解决这个问题吗?
  Delicious定义:对于一个字符串,我们认为它是Delicious的当且仅当它的每一个字符都属于一个 大于1的回文子串中。
Input
输入第一行一个正整数n,表示字符串长度。
接下来一行,一个长度为n只由大写字母A、B构成的字符串。
Output
输出仅一行,表示符合题目要求的子串的个数
Example
Input
5
A A B B B
1
2
Output
6

2.思路:这题主要考察思维能力,正难则反。
根据题意,可以发现不合法的串只有以下4种情况
ABB…B B
BAA…AA
AA…AAB
BB…BBA
因此分类枚举所有不合法情况,然后减去不合法的就行了。
我们可以发现当序列是AB或BA开头时,那么满足条件的子串个数就是对应序列长度减去2;而当序列是AA或BB开头时,当AA…AB或BB…A的情况时,需要额外减去1.
找到第i个元素后第一个A 和第一个B,然后分情况谈论即可(以A开头为例,B同理),如果B的位置在A之后,那就需要额外减1;如果B的位置在A之前,那就不需要额外减1;
综上所述,我们只要遍历一遍整个序列就可完成统计。

3.代码:

#include 
#include 
#define MAX 1000000
using namespace std;

int n;
int a[MAX], b[MAX], b1[MAX];

int main()
{
	char c;
	cin>>n;
	int cnt1, cnt2, temp1, temp2;
	long long int ans;
	cnt1 = 0, cnt2 = 0, ans = 0;
	for(int i=1;i<=n;i++)
	{
		cin>>c;
		a[i] = c - 'A';
		if(a[i]==0)
			b[cnt1++] = i;
		else
			b1[cnt2++] = i;
	}
	for(int i=1;i<=n-1;i++)
	{
		temp1 = lower_bound(b, b + cnt1, i + 1) - b;//找到第i个元素后第一个A 
        temp2 = lower_bound(b1, b1 + cnt2, i + 1) - b1;//找到第i个元素后第一个B 
        temp1 = b[temp1], temp2 = b1[temp2];
        if(a[i]==1)
        	swap(temp1, temp2);
        if(temp1!=0)
        {
        	if(temp2<temp1)
        		ans = ans + n - temp1 + 1;
        	else
        		ans = ans + n - temp1;
		}
	}
	cout<<ans<<endl;
}

CSP4
A-TT数鸭子
1.题意:TT来到一个小湖边,看到了许多在湖边嬉戏的鸭子,TT顿生羡慕。此时他发现每一只鸭子都不一样,或羽毛不同,或性格不同。TT在脑子里开了一个map<鸭子,整数> tong,把鸭子变成了一些数字。现在他好奇,有多少只鸭子映射成的数的数位中不同的数字个数小于k。

Input
输入第一行包含两个数n,k,表示鸭子的个数和题目要求的k。
接下来一行有n个数,aiai a_iai​,每个数表示鸭子被TT映射之后的值。

Output
输出一行,一个数,表示满足题目描述的鸭子的个数。
注意无行末空格
作业Week9、10+月模拟题3、4+CSP3、4+限时大模拟10、14_第1张图片

2.思路:这道题的重点是求一个数中不相同的数字个数。因此可以将这个数看成字符串,里面的每一个数字就是一个字符,设立一个大小为10的int数组.当某个数字出现的时候,这个数组的对应位置 str[ i ] - '0’处的值就为1,最后看有几个位置是1就可以得出有几个不同的数字.

3.代码:

#include 
#include
#include
#include
using namespace std;

char s[10];
int a[10];

int main()
{
	int n, k, count, sum;
	cin>>n>>k;
	count = 0;
	char c;
	for(int i=0;i<n;i++)
	{
		scanf("%s", s);
		sum = 0;
		for(int i=0;i<10;i++) 
			a[i]=0;
		for(int i=0;i<strlen(s);i++)
			if(!a[s[i]-'0'])
				a[s[i]-'0']++, sum++;
		if(sum<k)
			count++;	
	}
	cout<<count<<endl;
	return 0;
}

B-ZJM要抵御宇宙射线
1.题意:据传,2020年是宇宙射线集中爆发的一年,这和神秘的宇宙狗脱不了干系!但是瑞神和东东忙 于正面对决宇宙狗,宇宙射线的抵御工作就落到了ZJM的身上。假设宇宙射线的发射点位于一个 平面,ZJM已经通过特殊手段获取了所有宇宙射线的发射点,他们的坐标都是整数。而ZJM要构 造一个保护罩,这个保护罩是一个圆形,中心位于一个宇宙射线的发射点上。同时,因为大部分 经费都拨给了瑞神,所以ZJM要节省经费,做一个最小面积的保护罩。当ZJM决定好之后,东东 来找ZJM一起对抗宇宙狗去了,所以ZJM把问题扔给了你~

Input
输入 第一行一个正整数N,表示宇宙射线发射点的个数
接下来N行,每行两个整数X,Y,表示宇宙射线发射点的位置

Output
输出包括两行
第一行输出保护罩的中心坐标x,y 用空格隔开
第二行输出保护罩半径的平方
(所有输出保留两位小数,如有多解,输出x较小的点,如扔有多解,输入y较小的点)
无行末空格

2.思路:由于本题数据量较小(<=1000),因此可以直接暴力求解.
对于每一个点,求出距它最远的那个点的距离,然后找出其中最小的输出即可。
题目中要求如有多解,输出x较小的点,如仍有多解,输入y较小的点。因此只要将各点排序一下即可。
注意:最后输出的是半径的平方,不能开方。

3.代码:

#include 
#include
#include
#include
#include
using namespace std;

struct node
{
	long long int x, y;
	bool operator <(const node& m)
	{
		return x==m.x ? y<m.y : x<m.x;
	}
};

vector<node> vec;

int main()
{
	int n, x, y;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>x>>y;
		vec.push_back({x, y});
	}
	sort(vec.begin(), vec.end());
	long long int temp = 0, r = 0, x2 = 0, y2 = 0, r1 = 1e15;
	int index = 0;
	for(int i=0;i<n;i++)
	{
		r = 0;
		for(int j=0;j<n;j++)
		{
			x2 = vec[i].x - vec[j].x, y2 = vec[i].y - vec[j].y;
			x2 *=x2, y2 *=y2;
			temp = x2+y2;
			r = max(temp, r);
		}
		if(r<r1)
			r1=r, index = i;		
	}
	printf("%lld.00 %lld.00\n", vec[index].x, vec[index].y);
	printf("%lld.00\n", r1);
	return 0;
}

C-宇宙狗的危机
1.题意:在瑞神大战宇宙射线中我们了解到了宇宙狗的厉害之处,虽然宇宙狗凶神恶煞,但是宇宙狗有一个很可爱的女朋友。
最近,他的女朋友得到了一些数,同时,她还很喜欢树,所以她打算把得到的数拼成一颗树。
这一天,她快拼完了,同时她和好友相约假期出去玩。贪吃的宇宙狗不小心把树的树枝都吃掉了。所以恐惧包围了宇宙狗,他现在要恢复整棵树,但是它只知道这棵树是一颗二叉搜索树,同时任意树边相连的两个节点的gcd(greatest common divisor)都超过1。
但是宇宙狗只会发射宇宙射线,他来请求你的帮助,问你能否帮他解决这个问题

Input
输入第一行一个t,表示数据组数。
对于每组数据,第一行输入一个n,表示数的个数
接下来一行有n个数
a
i
ai a_i
a
i,输入保证是升序的。

Output
每组数据输出一行,如果能够造出来满足题目描述的树,输出Yes,否则输出No。
无行末空格。
作业Week9、10+月模拟题3、4+CSP3、4+限时大模拟10、14_第2张图片

2.思路:本题准备全遍历一下。在构造左孩子节点和右孩子节点时,都遍历各个可能的情况,但是如果每一次都这样查找的话无疑会爆掉。因此一定要合理剪枝,为此开辟了四个bool数组l1、r1和can_l、can_r。l1和r1记录对应的区间是否被遍历过,如果被遍历过那么就直接查看对应的can_l或can_r。如果没有被遍历过,那么就先遍历一下。查看其能否构造成符合标准的左子树或右子树。为了避免多余的遍历,当我们证明一个可行的建树策略后就直接结束遍历。
最后还开辟了一个二维数组result用于记录各个数据之间的公约数,避免重复的计算。

3.代码:

#include
#include
#include
#include
using namespace std;

int gcd(int a,int b)
{
	return b == 0 ? a : gcd(b,a%b);
}

int a[1000];
int n, judge;
int result[1000][1000];//记录最大公约数 
bool l1[1000][1000]; //统计左区间是否遍历过 
bool r1[1000][1000]; //统计右区间是否遍历过
bool can_l[1000][1000]; //记录左子树是否构建成功 
bool can_r[1000][1000]; //记录右子树是否构建成功 

bool gettree(int l, int r, int x)
{
	bool m = false;
	if(l>r)
		return true;
	for(int i=l;i<=r&&!m;i++)
	{
		if(result[x][i]>1)
		{
			if(!l1[l][i-1])
			{
				can_l[l][i-1] = gettree(l, i-1, i);
				l1[l][i-1] = true;
			} 
			if(!r1[i+1][r])
			{
				can_r[i+1][r] = gettree(i+1, r, i);
				r1[i+1][r] = true;
			} 
			if(can_l[l][i-1]&&can_r[i+1][r])
				m=true;
		}			
	}
	return m;
}

int main()
{
	int t;
	cin>>t;
	while(t!=0)
	{
		judge = false;
		memset(l1, false, sizeof(l1));
		memset(r1, false, sizeof(r1));
		memset(can_l, false, sizeof(can_l));
		memset(can_r, false, sizeof(can_r));
		cin>>n;
		for(int i=1;i<=n;i++)
			cin>>a[i];
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
			{
				result[i][j] = gcd(a[i], a[j]);
				result[j][i] = result[i][j];
			}
		for(int i=1;i<=n&&!judge;i++)
		{
			if(gettree(1, i-1, i)&&gettree(i+1, n, i))
				judge = true;	
		}
		if(!judge)
			cout<<"No"<<endl;
		else
			cout<<"Yes"<<endl;
		t--;
	}
}

Week9作业
A-咕咕东的目录管理器
1.题意:建造一个目录管理器,初始时硬盘是空的,命令行的当前目录为根目录 root。目录管理器可以理解为要维护一棵有根树结构,同时每个目录的儿子必须保持字典序。并依次实现下列操作:
作业Week9、10+月模拟题3、4+CSP3、4+限时大模拟10、14_第3张图片作业Week9、10+月模拟题3、4+CSP3、4+限时大模拟10、14_第4张图片
输出格式为:
在这里插入图片描述
Input
输入文件包含多组测试数据,第一行输入一个整数表示测试数据的组数 T (T <= 20);
每组测试数据的第一行输入一个整数表示该组测试数据的命令总数 Q (Q <= 1e5);
每组测试数据的 2 ~ Q+1 行为具体的操作 (MKDIR、RM 操作总数不超过 5000);
面对数据范围你要思考的是他们代表的 “命令” 执行的最大可接受复杂度,只有这样你才能知道你需要设计的是怎样复杂度的系统。

Output
每组测试数据的输出结果间需要输出一行空行。注意大小写敏感。

2.思路:题目要求一个目录能够根据子目录的名字取到它的子目录
故要用 map,它可以根据 key 也就是 string 在内部进行排序。这样每次可以 log 级别复杂度取到子目录。
MKDIR s, 创建子目录操作:因为map可以按照key也就是string就行排序,那么直接向children数组中插入名字为s的目录即可,如果已存在同名子目录返回空指针。且为了后续的撤销操作,需要将插入的子目录存储到对应的cmlist数组中,撤销时调用RM操作即可。
RM s, 删除子目录操作:与插入操作基本一致,就是改为如果不存在目录名为s的子目录返回空指针,撤销时调用addchild函数即可,addchild函数具体实现与MKDIR基本一致。
CD s, 进入子目录操作:具体操作较为简单,就是要为撤销做准备,如果执行成功就将当前的目录存储到对应的cmlist数组中,然后再更新当前目录。撤销时直接从cmlist数组取出对应的目录,然后更新now即可。
SZ和LS都较为简单,就是TREE操作需要引入一个懒更新,避免重复遍历(否则会超时),为此需要引入一个bool类型的updated来记录当前的目录是否已经遍历过以及一个vector< string>* tenDescendants来保存当前目录的十个后代;
更新可以直接通过前序遍历直接更新十个后代;也可以先更新前五个,再更新后五个以避免多余的遍历。

3.代码:

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

bool status = false;

struct Command
{
	const string CMDNAMES[7]={"MKDIR","RM","CD","SZ","LS","TREE","UNDO"};
	int type;
	Command(string s)
	{
		for(int i=0;i<7;i++)
		{
			if(CMDNAMES[i] == s)
			{
				type=i;
				return;
			}
		}
	} 
};


struct ContentNode
{
   	string element;
   	int size; 
   	ContentNode **child;
   	ContentNode *father;
     
   	ContentNode(string thePair):element(thePair)
	{
   		size = 0;
   		child = NULL;
	}
    ContentNode(string thePair, int dsize)
            :element(thePair)
	{
        size = dsize;
        if(dsize!=0)
			child = new ContentNode* [dsize];
	}
    bool operator <(const ContentNode&t)
	{
    	return element<t.element;
	}
};

vector<string> now;//记录当前目录 
vector<int> act;//记录进行的操作,MKDIR或RM或CD
vector<string> s;//记录操作的目录 
vector<ContentNode*> cmd;//用于记录被删除的结点 

class Content
{
	public:
		Content()
		{
			string m = "root";
			root = new ContentNode(m);
		}
		~Content(){};
		void undo();
		void sz();
		void ls();
		void tree();
		void insert(string e);
		void insert(ContentNode* t1);
		void delete1(string e);
		void cd(string e);
		int getsize(ContentNode* t1);
	private:
		ContentNode *root;
		bool exist(ContentNode* t1, string e);
		void tree(ContentNode* t1, int &num, int &size1);
		ContentNode* preOrderfind(ContentNode *t,string e);
		ContentNode* prepare(ContentNode* t1, ContentNode* t2);
};
ContentNode* Content::preOrderfind(ContentNode *t,string e)//使用递归查找元素weie的节点 
{
    ContentNode *p= NULL;
    int m = t->size, i = 0;
    if (t != NULL)
    {
        if(t->element==e)
        {
            p=t;
            return p;
        }
        while(i<m)
        {
        	p = preOrderfind(t->child[i], e);
        	if(p!=NULL)
        		return p;
        	i++;
		}
    }
    return NULL;
}
bool Content::exist(ContentNode* t1, string e)
{
	int dsize = t1->size;
	for(int i=0;i<dsize;i++)
	{
		ContentNode* node2 = t1->child[i];
		if(node2->element == e)
			return true;
	}
	return false;
}
ContentNode* Content::prepare(ContentNode* t1, ContentNode* t2)
{
	string element = t1->element;
	int dsize = t1->size+1;
	ContentNode* node = new ContentNode(element,dsize);
	if(dsize == 1)
	{
		node->child[0]=t2;
		t2->father = node;
		return node;
	}
	int num = 0;
	string e = t2->element;
	for(int i=0;i<dsize-1;i++)
	{
		if(e > t1->child[i]->element)
			num++;
	}
	for(int i=0;i<dsize;i++)
	{
		if(i>=num&&i!=0)
		{
			node->child[i] = t1->child[i-1];
			t1->child[i-1]->father = node;
		}	
		else
		{
			node->child[i] = t1->child[i];
			t1->child[i]->father = node;
		}	
	}
	node->child[num] = t2;
	t2->father = node;
	return node;
}
void Content::insert(string e)
{
	ContentNode* node = new ContentNode(e);
	this->insert(node);
}
void Content::insert(ContentNode* node2)
{
	string m = now[now.size() - 1];
	ContentNode* node1 = this->preOrderfind(root, m);
	string e = node2->element; 
	if(exist(node1, e))
	{
		printf("ERR\n");
		return;
	}
	ContentNode* node3 = node1 -> father;
	ContentNode* dnode = prepare(node1, node2);
	if(!status)
		s.push_back(e);
	if(node1->element == "root")
		root = dnode;	
	else
	{
		for(int i=0;i<node3->size;i++)
		{
			node2 = node3->child[i];
			if(node1->element == node2->element)
			{
				if(node3->element == "root")
				{
					root->child[i] = dnode;
					dnode->father = root;
				}	
				else
				{
					node3->child[i] = dnode;
					dnode->father = node3;
				}		
			}	
		}
	}
	if(!status)
		act.push_back(0);
	printf("OK\n");	
}
void Content::delete1(string e)
{
	string m = now[now.size()-1];
	ContentNode* node1 = this->preOrderfind(root, m);
	if(!exist(node1, e))
	{
		printf("ERR\n");
		return;
	}
	ContentNode* node2 = new ContentNode(node1->element);
	ContentNode* node3 = node1->father;
	for(int i=0;i<node1->size;i++)
	{
		if(node1->child[i]->element != e)
			node2 = prepare(node2, node1->child[i]);
		else if(!status)
			cmd.push_back(node1->child[i]);
	}	
	if(node1->element =="root")
		root = node2;
	else if(node3->element =="root")
	{
		for(int i=0;i<root->size;i++)
		{
			ContentNode* dnode = root->child[i];
			if(dnode->element==node1->element)
			{
				root->child[i] = node2;
				node2->father = root;
			}		
		}
	}
	else
	{
		for(int i=0;i<node3->size;i++)
		{
			ContentNode* dnode = node3->child[i];
			if(dnode->element==node1->element)
			{
				node3->child[i] = node2;
				node2->father = node3;
			}		
		}
	}
	if(!status)
		act.push_back(1);
	printf("OK\n");
}
void Content::cd(string e)
{
	string m = now[now.size()-1];
	ContentNode* node1 = this->preOrderfind(root, m);
	if(!exist(node1, e)&&e!="..")
	{
		printf("ERR\n");
		return;
	}
	if(e!="..")
	{
		now.push_back(e);
		for(int i=0;i<node1->size;i++)
			ContentNode* node2 = node1->child[i];
		printf("OK\n");
	}
	else
	{
		string t = "..";
		now.pop_back();
		s.push_back(m);
		s.push_back(t);
		if(!now.empty())
			printf("OK\n");
		else
		{
			now.push_back(m);
			printf("ERR\n");
		}		
	}
	act.push_back(2);
}
void Content::sz()
{
	string m = now[now.size()-1];
	ContentNode* node1 = this->preOrderfind(root, m);
	printf("%d\n", getsize(node1) + 1);
}
void Content::ls()
{
	string m = now[now.size()-1];
	ContentNode* node1 = this->preOrderfind(root, m);
	if(node1->size>=1&&node1->size<=10)
	{
		for(int i=0;i<node1->size;i++)
		{
			ContentNode* node2 = node1->child[i];
			cout<<node2->element<<endl;
		}
	}
	else if(node1->size==0)
		printf("EMPTY\n");
	else 
	{
		for(int i=0;i<5;i++)
		{
			ContentNode* node2 = node1->child[i];
			cout<<node2->element<<endl;
		}
		printf("...\n");
		for(int i=node1->size-1;i>node1->size-5;i--)
		{
			ContentNode* node2 = node1->child[i];
			cout<<node2->element<<endl;
		}
	}
}
void Content::tree(ContentNode *t, int &num, int &size1)//前序遍历 
{
	num++;
	if(num<=5||num>size1-4)
		cout<<t->element<<endl;
	if(num==5&&size1>10)
		printf("...\n");
	for(int i=0;i<t->size;i++)
	{
		ContentNode* node1 = t->child[i];
		tree(node1, num, size1);
	} 
}
void Content::tree()
{
	string m = now[now.size()-1];
	ContentNode* node1 = this->preOrderfind(root, m);
	int size1 = getsize(node1), num = 0;
	this->tree(node1, num, size1);
}
int Content::getsize(ContentNode *t)
{
	int size1 = 0;
	size1 = size1+t->size;
	for(int i=0;i<t->size;i++)
	{
		ContentNode* node1 = t->child[i];
		size1 = size1 + getsize(node1);
	} 
	return size1;
}
void Content::undo()
{
	if(act.empty())
	{
		printf("ERR\n");
		return;
	}
	int m = act[act.size()-1];
	string e = s[s.size()-1];
	act.pop_back();
	status = true;
	switch(m)
	{
		case 0:
		{
			this->delete1(e);
			s.pop_back();
			break;
		}
		case 1:
		{
			ContentNode* node = cmd[cmd.size()-1];
			this->insert(node);
			cmd.pop_back();
			break;
		}
		case 2:
		{
			if(e=="..")
			{
				s.pop_back();
				e = s[s.size()-1];
				now.push_back(e);
				s.pop_back();
			}
			else
				now.pop_back();
			printf("OK\n");
			break;
		}
	}
	status = false;
}
int main()
{
	int t, q;
	string s1, e;
	scanf("%d", &t);
	for(int i=0;i<t;i++) 
	{
		scanf("%d", &q);
		Content c1;
		s.clear(), act.clear(), now.clear();
		string e1 = "root";
		now.push_back(e1);
		for(int j=0;j<q;j++)
		{
			cin>>s1;
			Command *cmd=new Command(s1);
			switch(cmd->type)
			{
				case 0:
				{
					cin>>e;
					c1.insert(e);
					break;
				}
				case 1:
				{
					cin>>e;
					c1.delete1(e);
					break;
				}
				case 2:
				{
					cin>>e;
					c1.cd(e);
					break;
				}
				case 3:
				{
					c1.sz();
					break;
				}
				case 4:
				{
					c1.ls();
					break;
				}
				case 5:
				{
					c1.tree();
					break;
				}
				case 6:
				{
					c1.undo();
					break;
				}
			}
		}
		c1.~Content(); 
		cout<<endl;
	}
	return 0;
}

B-东东学打牌
1.题意:
最近,东东沉迷于打牌。所以他找到 HRZ、ZJM 等人和他一起打牌。由于人数众多,东东稍微修改了亿下游戏规则:
所有扑克牌只按数字来算大小,忽略花色。
每张扑克牌的大小由一个值表示。A, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K 分别指代 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13。
每个玩家抽得 5 张扑克牌,组成一手牌!(每种扑克牌的张数是无限的,你不用担心,东东家里有无数副扑克牌)
理所当然地,一手牌是有不同类型,并且有大小之分的。
举个栗子,现在东东的 “一手牌”(记为 α),瑞神的 “一手牌”(记为 β),要么 α > β,要么 α < β,要么 α = β。
那么这两个 “一手牌”,如何进行比较大小呢?首先对于不同类型的一手牌,其值的大小即下面的标号;对于同类型的一手牌,根据组成这手牌的 5 张牌不同,其值不同。下面依次列举了这手牌的形成规则:
(1)大牌:这手牌不符合下面任一个形成规则。如果 α 和 β 都是大牌,那么定义它们的大小为组成这手牌的 5 张牌的大小总和。
(2)对子:5 张牌中有 2 张牌的值相等。如果 α 和 β 都是对子,比较这个 “对子” 的大小,如果 α 和 β 的 “对子” 大小相等,那么比较剩下 3 张牌的总和。
(3)两对:5 张牌中有两个不同的对子。如果 α 和 β 都是两对,先比较双方较大的那个对子,如果相等,再比较双方较小的那个对子,如果还相等,只能比较 5 张牌中的最后那张牌组不成对子的牌。
(4)三个:5 张牌中有 3 张牌的值相等。如果 α 和 β 都是 “三个”,比较这个 “三个” 的大小,如果 α 和 β 的 “三个” 大小相等,那么比较剩下 2 张牌的总和。
(5)三带二:5 张牌中有 3 张牌的值相等,另外 2 张牌值也相等。如果 α 和 β 都是 “三带二”,先比较它们的 “三个” 的大小,如果相等,再比较 “对子” 的大小。
(6)炸弹:5 张牌中有 4 张牌的值相等。如果 α 和 β 都是 “炸弹”,比较 “炸弹” 的大小,如果相等,比较剩下那张牌的大小。
(7)顺子:5 张牌中形成 x, x+1, x+2, x+3, x+4。如果 α 和 β 都是 “顺子”,直接比较两个顺子的最大值。
(8)龙顺:5 张牌分别为 10、J、Q、K、A。
作为一个称职的魔法师,东东得知了全场人手里 5 张牌的情况。他现在要输出一个排行榜。排行榜按照选手们的 “一手牌” 大小进行排序,如果两个选手的牌相等,那么人名字典序小的排在前面。
不料,此时一束宇宙射线扫过,为了躲避宇宙射线,东东慌乱中清空了他脑中的 Cache。请你告诉东东,全场人的排名

Input
输入包含多组数据。每组输入开头一个整数 n (1 <= n <= 1e5),表明全场共多少人。
随后是 n 行,每行一个字符串 s1 和 s2 (1 <= |s1|,|s2| <= 10), s1 是对应人的名字,s2 是他手里的牌情况。

Output
对于每组测试数据,输出 n 行,即这次全场人的排名。

2.思路:通过分析8种牌型,我们可以知道为了比较各种牌,我们除了要知道这五张牌的牌型外,还要知道sum, p1, p2三个排序关键字,其中sum是5张牌种个数为1的牌的数值和;当牌型为两对时,p1记录的是两对种较大的那一对的数值,p2记录的是两对中较小的那一对的数值;当牌型为三带二时,p1记录的是三条的数值,p2记录的是一对的数值;依次类推,p1记录的始终是比较优先级更高的数值。然后重载<,依次按照牌型,p1,p2,sum降序排列,如果前四者都相同,则按照名字的字典序升序排列。

3.代码:

#include 
#include 
#include 
using namespace std;

struct card
{
	string s;
	int type, sum, p1, p2;
	bool operator < (const card &c) const
	{
		if(type != c.type)
			return type>c.type;
		else if(p1 != c.p1)
			return p1>c.p1;
		else if(p2 != c.p2)
			return p2>c.p2;
		else if(sum != c.sum)
			return sum > c.sum;
		else
			return s < c.s; 		
	}
};

void solve(string s, card &num)
{
	int j=0, a[14] = {0}, b[5] = {0};
	int sum = 0, c0 =0, c1 = 0, c2 = 0;
	for(int i=0;i<s.size();i++)
	{
		if(s[i+1] =='0')
		{
			b[j] = 10;
			i++;
		}
		else if(s[i]=='A')
			b[j] = 1;
		else if(s[i]=='J')
			b[j] = 11;
		else if(s[i]=='Q')
			b[j] = 12;
		else if(s[i]=='K')
			b[j] = 13;
		else 
			b[j] = s[i] - '0';
		j++;	
	}
	sort(b, b+5);
	int p1 = 0, p2 = 0;
	for(int i=0;i<5;i++)
		a[b[i]]++;
	for(int i=1;i<14;i++)
	{
		if(a[i]==2)
		{
			c0++;
			if(!p2)
				p2 = i;
			else
				p1 = i;
		}	
		else if(a[i]==3)
		{
			c1++;
			p1 = i;
		}		
		else if(a[i]==4)
		{
			c2++;
			p1 = i;
		}	
		else if(a[i]==1)
			sum +=i;
	}
	num.sum = sum;
	num.type = 1, num.p1 = p1, num.p2 = p2;
	if(c0==1 && c1==0)
		num.type = 2;
	else if(c0==2)
		num.type = 3;
	else if(c1==1 && c0==0)
		num.type = 4;
	else if(c1==1 && c0==1)
		num.type = 5;
	else if(c2==1)
		num.type = 6;
	else if(b[4] - b[0] == 4)
		num.type = 7;
	else if(b[4] - b[1] == 3 && b[1] - b[0] == 9)
		num.type = 8;
}

int main()
{
	string S;
	int n;
	card* c = new card[10001];
	while(scanf("%d", &n)!=EOF)
	{
		for(int i=0;i<n;i++)
		{
			cin>>c[i].s>>S;
			solve(S, c[i]);
		}
		sort(c, c + n);
		for(int i=0;i<n;i++)
			cout<<c[i].s<<endl;
	}
	return 0;
}

C-签到题
1.题意:SDUQD 旁边的滨海公园有 x 条长凳。第 i 个长凳上坐着 a_i 个人。这时候又有 y 个人将来到公园,他们将选择坐在某些公园中的长凳上,那么当这 y 个人坐下后,记k = 所有椅子上的人数的最大值,那么k可能的最大值mx和最小值mn分别是多少。

Input
第一行包含一个整数 x (1 <= x <= 100) 表示公园中长椅的数目
第二行包含一个整数 y (1 <= y <= 1000) 表示有 y 个人来到公园
接下来 x 个整数 a_i (1<=a_i<=100),表示初始时公园长椅上坐着的人数

Output
输出 mn 和 mx

2.思路:首先,将现有的数组a进行排序,最大值就是让y个人全部坐在目前人最多的那个长椅上,即mx=a[n-1]+y。
然后最小值就是要让每个长椅上的人尽可能地均匀,有两种情况:
(1)当y不足以分配给其他长椅使他们的数值都达到a[n-1]时,那么最小值就是a[n-1];
(2)当y足以分配给其他长椅使他们的数值都达到a[n-1]时,先分配,即让所有的长椅的人数都达到k,然后剩下的人平均分给x个长椅,然后最多的那个即为mn.
最后依次输出mn和mx即可。

3.代码:

#include 
#include
using namespace std;

int a[101];

int main()
{
	int n, num, mx, mn, max1, sum;
	cin>>n>>num;
	for(int i=0;i<n;i++)
		cin>>a[i];
	sort(a, a+n);
	max1 = a[n-1];
	mn = max1 , sum = 0, mx = max1 + num;
	for(int i=0;i<n;i++)
		sum = sum + max1 - a[i];
	if(sum<num)
	{
		sum = num - sum;
		mn = sum/n + mn;
		if(sum%n!=0)
			mn++;
	}
	cout<<mn<<" "<<mx;
	return 0;
}

Week10作业
A-签到题
1.题意:东东在玩游戏“Game23”。
在一开始他有一个数字n,他的目标是把它转换成m,在每一步操作中,他可以将n乘以2或乘以3,他可以进行任意次操作。输出将n转换成m的操作次数,如果转换不了输出-1。

Input
输入的唯一一行包括两个整数n和m(1<=n<=m<=5*10^8).

Output
输出从n转换到m的操作次数,否则输出-1.

2.题意:该问题较为简单,由题意知,转换时只能乘以2或3,故转换过程有且只有一组解。所以我们只需使用两个while循环便可求出答案。

3.代码:

#include 
using namespace std;

int sum;

bool judge(int m, int n)
{
	int s = m/n;
	if(m%n!=0)
		return false;
	while(s%2==0&&s!=0)
	{
		sum++;
		s=s/2;
	}
	while(s%3==0&&s!=0)
	{
		sum++;
		s=s/3;
	}
	if(s==1)
		return true;
	else
		return false;
}

int main()
{
	int m, n;
	cin>>m>>n;
	sum = 0;
	if(judge(n, m))
		cout<<sum<<endl;
	else
		cout<<-1<<endl;
	return 0;
}

B-LIS&LCS
1.题意:东东有两个序列A和B。
他想要知道序列A的LIS和序列AB的LCS的长度。
注意,LIS为严格递增的,即a1

Input
第一行两个数n,m(1<=n<=5,000,1<=m<=5,000)
第二行n个数,表示序列A
第三行m个数,表示序列B

Output
输出一行数据ans1和ans2,分别代表序列A的LIS和序列AB的LCS的长度

2.思路:
一、
对于数组A,求解LIS的过程如下:
定义 fi 表示以 Ai 为结尾的最长上升序列的方程。
初始化时f1 = 1,转移过程如下:
在这里插入图片描述
LIS的长度为max{f[i], i=1…n }
此外也可以调用LCS函数来计算LIS,求出A数组和按升序排列的A数组的LCS
长度即可。
注:因为要求解的LIS为严格递增的,所以A数组排完序后需要将重复的元素覆盖掉。

二、
对于数组a, b,求解LCS 的过程如下(A的size为m, B的size为n)。
假设f[i][j] 为 a1, a2, …, ai 和 b1, b2, …, bj 的 LCS 长度
初始时f[1][0] = f[0][1] = f[0][0] = 0
当 ai == bj 时,f[i][j] = f[i-1][j-1] + 1,否则 f[i][j] = max(f[i-1][j], f[i][j-1])
然后f[m][n]的值即为LCS 的长度。

3.代码:

#include 
#include 
#include 
using namespace std;

int a[5001], b[5001], c[5001];
int f[5001][5001];

void LCS(int *a, int *b, int m, int n)
{
	f[1][0] = f[0][1] = f[0][0] = 0;
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++)
		{
			if(a[i]==b[j])
				f[i][j] = f[i-1][j-1] + 1;
			else
				f[i][j] = max(f[i-1][j], f[i][j-1]);
		}
	cout<<f[m][n];
}

int main()
{
	int m, n;
	cin>>m>>n;
	for(int i=1;i<=m;i++)
	{
		cin>>a[i];
		c[i] = a[i];
	}	
	for(int i=1;i<=n;i++)
		cin>>b[i];
	sort(c+1, c+m+1);
	for(int i=1;i<=m;i++)
		if(c[i]==c[i-1])
			c[i-1]=1e9;
	LCS( a, c, m, m);
	cout<<" ";
	LCS( a, b, m, n);
	return 0;
} 

C-拿数问题
1.题意:YJQ 上完第10周的程序设计思维与实践后,想到一个绝妙的主意,他对拿数问题做了一点小修改,使得这道题变成了 拿数问题 II。
给一个序列,里边有 n 个数,每一步能拿走一个数,比如拿第 i 个数, Ai = x,得到相应的分数 x,但拿掉这个 Ai 后,x+1 和 x-1 (如果有 Aj = x+1 或 Aj = x-1 存在) 就会变得不可拿(但是有 Aj = x 的话可以继续拿这个 x)。求最大分数。

Input
第一行包含一个整数 n (1 ≤ n ≤ 105),表示数字里的元素的个数
第二行包含n个整数a1, a2, …, an (1 ≤ ai ≤ 105)

Output
输出一个整数:n你能得到最大分值。

2.思路:本题与上课所讲主要是存储方式不同,对于数值x,数组a中a[x]为其出现的次数。max为x中的最大值,之后计算过程与上课讲的类似。
dp[i] , 仅考虑 A[1…i] ,能拿到的最大分数
初始时dp[0] = 0, dp[1] = a[1].
dp[i] = max(dp[i-1], dp[i-2]+a[i]*i);
然后输出dp[max1]即可。
同时因1 ≤ n ≤ 100000和1 ≤ ai ≤ 100000,故最终结果用long long int来表示。

3.代码:

#include 
#include 
#include 
using namespace std;

int a[100001];
long long int point[100001];

int main()
{
	int n, m, sum, max1;
	while(scanf("%d", &n)!=EOF)
	{
		memset(a, 0, sizeof(a));
		memset(point, 0, sizeof(point));
		max1 = 0;
		for(int i=0;i<n;i++)
		{
			scanf("%d", &m);
			a[m]++;
			max1 = max(max1, m);
		}
		point[0] = 0, point[1] = a[1];
		for(int i=2;i<=max1;i++)
		{
			long long int temp =(long long int) a[i]*i;
			point[i] = max(point[i-1], point[i-2]+temp);
		}
		printf("%lld\n", point[max1]);
	}
	return 0;
}

月模拟题3-炉石传说
1.题意:《炉石传说:魔兽英雄传》(Hearthstone: Heroes of Warcraft,简称炉石传说)是暴雪娱乐开发的一款集换式卡牌游戏(如下图所示)。
作业Week9、10+月模拟题3、4+CSP3、4+限时大模拟10、14_第5张图片
游戏在一个战斗棋盘上进行,由两名玩家轮流进行操作,本题所使用的炉石传说游戏的简化规则如下:
  * 玩家会控制一些角色,每个角色有自己的生命值和攻击力。当生命值小于等于 0 时,该角色死亡。角色分为英雄和随从。
  * 玩家各控制一个英雄,游戏开始时,英雄的生命值为 30,攻击力为 0。当英雄死亡时,游戏结束,英雄未死亡的一方获胜。
  * 玩家可在游戏过程中召唤随从。棋盘上每方都有 7 个可用于放置随从的空位,从左到右一字排开,被称为战场。当随从死亡时,它将被从战场上移除。
  * 游戏开始后,两位玩家轮流进行操作,每个玩家的连续一组操作称为一个回合。
  * 每个回合中,当前玩家可进行零个或者多个以下操作:
  1) 召唤随从:玩家召唤一个随从进入战场,随从具有指定的生命值和攻击力。
  2) 随从攻击:玩家控制自己的某个随从攻击对手的英雄或者某个随从。
  3) 结束回合:玩家声明自己的当前回合结束,游戏将进入对手的回合。该操作一定是一个回合的最后一个操作。
  * 当随从攻击时,攻击方和被攻击方会同时对彼此造成等同于自己攻击力的伤害。受到伤害的角色的生命值将会减少,数值等同于受到的伤害。例如,随从 X 的生命值为 HX、攻击力为 AX,随从 Y 的生命值为 HY、攻击力为 AY,如果随从 X 攻击随从 Y,则攻击发生后随从 X 的生命值变为 HX - AY,随从 Y 的生命值变为 HY - AX。攻击发生后,角色的生命值可以为负数。
  本题将给出一个游戏的过程,要求编写程序模拟该游戏过程并输出最后的局面。
  
Input
输入第一行是一个整数 n,表示操作的个数。接下来 n 行,每行描述一个操作,格式如下:
   …
  其中表示操作类型,是一个字符串,共有 3 种:summon表示召唤随从,attack表示随从攻击,end表示结束回合。这 3 种操作的具体格式如下:
  * summon :当前玩家在位置召唤一个生命值为、攻击力为的随从。其中是一个 1 到 7 的整数,表示召唤的随从出现在战场上的位置,原来该位置及右边的随从都将顺次向右移动一位。
  * attack :当前玩家的角色攻击对方的角色 。是 1 到 7 的整数,表示发起攻击的本方随从编号,是 0 到 7 的整数,表示被攻击的对方角色,0 表示攻击对方英雄,1 到 7 表示攻击对方随从的编号。
  * end:当前玩家结束本回合。
  注意:随从的编号会随着游戏的进程发生变化,当召唤一个随从时,玩家指定召唤该随从放入战场的位置,此时,原来该位置及右边的所有随从编号都会增加 1。而当一个随从死亡时,它右边的所有随从编号都会减少 1。任意时刻,战场上的随从总是从1开始连续编号。
数据规模:
  * 操作的个数0 ≤ n ≤ 1000。
  * 随从的初始生命值为 1 到 100 的整数,攻击力为 0 到 100 的整数。
  * 保证所有操作均合法,包括但不限于:
   1) 召唤随从的位置一定是合法的,即如果当前本方战场上有 m 个随从,则召唤随从的位置一定在 1 到 m + 1 之间,其中 1 表示战场最左边的位置,m + 1 表示战场最右边的位置。
   2) 当本方战场有 7 个随从时,不会再召唤新的随从。
   3) 发起攻击和被攻击的角色一定存在,发起攻击的角色攻击力大于 0。
   4) 一方英雄如果死亡,就不再会有后续操作。
数据约定:
  前 20% 的评测用例召唤随从的位置都是战场的最右边。
  前 40% 的评测用例没有 attack 操作。
  前 60% 的评测用例不会出现随从死亡的情况。
  
Output
输出共 5 行:
  第 1 行包含一个整数,表示这 n 次操作后(以下称为 T 时刻)游戏的胜负结果,1 表示先手玩家获胜,-1 表示后手玩家获胜,0 表示游戏尚未结束,还没有人获胜。
  第 2 行包含一个整数,表示 T 时刻先手玩家的英雄的生命值。
  第 3 行包含若干个整数,第一个整数 p 表示 T 时刻先手玩家在战场上存活的随从个数,之后 p 个整数,分别表示这些随从在 T 时刻的生命值(按照从左往右的顺序)。
  第 4 行和第 5 行与第 2 行和第 3 行类似,只是将玩家从先手玩家换为后手玩家。

Example
Input
8
summon 1 3 6
summon 2 4 2
end
summon 1 4 5
summon 1 2 1
attack 1 2
end
attack 1 1

12345678910
Output
0
30
1 2
30
1 2

2.思路:首先构建一个结构体,用于存储英雄和随从的攻击力和血量。利用vector数组分别存储先手和后手玩家,a[0]为先手玩家,a[1]为后手玩家。先手和后手的交换可以通过(m+1)%2或!m实现。
直接调用vector数组完成数据的插入和删除。需要注意的就是当一方英雄血量<=0时,不需要删除元素,还有就是输出的血量可能为负数。

3.代码:

#include 
#include 
#include 
#include 
#include 
using namespace std;

struct servant
{
	int life, att;
	servant(int a, int b)
	{
		life = a, att = b;
	}
};
vector<servant> a[2];

int main()
{
	int n, m, num, num1, m1;
	int attack, life;
	cin>>n;
	//scanf("%d", &n);
	string s;
	m = 0;
	a[0].push_back({30, 0});
	a[1].push_back({30, 0});
	for(int i=0;i<n;i++)
	{
		cin>>s;
		if(s=="summon")
		{
			cin>>num>>attack>>life;
			a[m].insert(a[m].begin()+num, {life, attack});
		}
		if(s=="attack")
		{
			cin>>num>>num1;
			m1 = (m+1)%2;
			a[m][num].life -= a[m1][num1].att;
			a[m1][num1].life -= a[m][num].att;
			if(a[m][num].life<=0&&num!=0)
				a[m].erase(a[m].begin()+num);
			if(a[m1][num1].life<=0&&num1!=0)
				a[m1].erase(a[m1].begin()+num1);		
		}
		if(s=="end")
			m = (m+1)%2;
	}
	if(a[0][0].life<=0)
		cout<<-1<<endl;
		printf("-1\n");
	else if(a[1][0].life<=0)
		cout<<1<<endl;
		printf("1\n");
	else 
		cout<<0<<endl;
		printf("0\n");	
	cout<<a[0][0].life<<endl;
	printf("%d\n", a[0][0].life);
	cout<<a[0].size()-1<<" ";
	printf("%d ", a[0].size()-1);
	for(int i=1;i<a[0].size();i++)
		printf("%d ", a[0][i]);
	printf("\n");
	printf("%d\n", a[1][0].life);
	printf("%d ", a[1].size()-1);
	for(int i=1;i<a[1].size();i++)
		printf("%d ", a[1][i]);
	printf("\n");
	return 0;
}

月模拟题4-元素模拟器
1.题意:作业Week9、10+月模拟题3、4+CSP3、4+限时大模拟10、14_第6张图片作业Week9、10+月模拟题3、4+CSP3、4+限时大模拟10、14_第7张图片作业Week9、10+月模拟题3、4+CSP3、4+限时大模拟10、14_第8张图片作业Week9、10+月模拟题3、4+CSP3、4+限时大模拟10、14_第9张图片
2.思路:定义元素结构体element,内含标签、id、行数、级数四个属性。
文档读入时,判断其标签属性,并使用transform函数并将其全部转为小写,id属性不变,同时还要记录其行号和级数,将其存放于element类型的一个数组的中,其索引即为元素下标。
读入元素选择器,利用vector存储。
有空格则间断,标签属性全部转为小写。然后对vector中内容进行逐步查找,在查找过程中,记录下一步查找的起始行和最小级。如果是查找的最后一步,即vector中的最后一个元素,则查找到元素相等且级数大于最小级的元素存入vector中即可,即为答案。如果不是,则使用提示的贪心策略,找到层级最小的匹配项。

3.代码:

#include 
#include 
#include 
#include 
#include 
using namespace std;

struct element
{
	string label, id;//标签、id 
	int row;  //行
	int level;  //级
	element(string lab, string i, int rw, int lev)
	{
		label = lab;
		id = i;
		row = rw;
		level = lev;
	}
	element(){}
}elem[101];

vector<string> p;
vector<int> ans;
int n, m;

void solve()
{
	string s;
	getline(cin, s, '\n');
	p.clear(); //清空
	int t = 0, tt = 0; //查找位置
	while (true)
	{
		string str;
		t = s.find(" ",tt);
		if(t==-1)
			str = s.substr(tt);
		else
			str = s.substr(tt, t - tt); 
		if (str[0]!='#')
			transform(str.begin(), str.end(), str.begin(), ::tolower);
		p.push_back(str);
		if (t == -1) 
			break;  //不存在,退出
		tt = t + 1;
	}
}
void find()
{
	ans.clear();
	int rw = -1, lev = -1;//行数、级数 
	for (int i = 0; i < p.size(); i++)
	{
		if (i == p.size() - 1) //最后一级
		{
			for (int j = rw + 1; j < n; j++)
				if ((elem[j].label == p[i] || elem[j].id == p[i]) && elem[j].level > lev)
					ans.push_back(elem[j].row);
		}
		else  //前几级
		{
			if (lev = -1) lev = n + 1;
			for (int j = rw + 1; j < n; j++)  //查找级数最低的
			{
				if ((elem[j].label == p[i] || elem[j].id == p[i]) && elem[j].level < lev)
				{
					rw = j;  
					lev = elem[j].level; 
				}
			}
		}
	}
}

int main()
{
	cin>>n>>m; 
	getchar();
	for (int i = 0; i < n; i++)
	{
		string s, lab, id;
		getline(cin, s, '\n');
		int lev = 0, t = 0;
		while (true)
		{
			t = s.find('.',lev);
			if (t ==-1) 
				break;
			lev++;
		}
		t = s.find(" "); //查找空格
		if (t == -1)
		{
			lab = s.substr(lev);
			id = " ";
		}
		else
		{
			lab = s.substr(lev, t - lev);
			id = s.substr(t + 1);
		}
		transform(lab.begin(), lab.end(), lab.begin(), ::tolower);//标签小写转
		elem[i] = element(lab, id, i+1, lev / 2);
	}
	for (int i = 0; i < m; i++)
	{
		solve();
		find();
		cout<<ans.size();
		for(int i = 0 ; i < ans.size() ; i++)
			cout <<" "<< ans[i];
		cout << endl;
	}
	return 0;
}

Week14-猫睡觉问题
1.题意:众所周知,TT家里有一只魔法喵。这只喵十分嗜睡。一睡就没有白天黑夜。喵喵一天可以睡多次!!每次想睡多久就睡多久╭(╯^╰)╮
喵睡觉的时段是连续的,即一旦喵喵开始睡觉了,就不能被打扰,不然喵会咬人哒[○・`Д´・ ○]
可以假设喵喵必须要睡眠连续不少于 A 个小时,即一旦喵喵开始睡觉了,至少连续 A 个小时内(即A*60分钟内)不能被打扰!
现在你知道喵喵很嗜睡了,它一天的时长都在吃、喝、拉、撒、睡,换句话说要么睡要么醒着滴!
众所周知,这只魔法喵很懒,和TT一样懒,它不能连续活动超过 B 个小时。
猫主子是不用工作不用写代码滴,十分舒适,所以,它是想睡就睡滴。
但是,现在猫主子有一件感兴趣的事,就是上BiliBili网站看的新番。
新番的播放时间它已经贴在床头啦(每天都用同一张时间表哦),这段时间它必须醒着!!
作为一只喵喵,它认为安排时间是很麻烦的事情,现在请你帮它安排睡觉的时间段。

Input
多组数据,多组数据,多组数据哦,每组数据的格式如下:
第1行输入三个整数,A 和 B 和 N (1 <= A <= 24, 1 <= B <= 24, 1 <= n <= 20)
第2到N+1行为每日的新番时间表,每行一个时间段,格式形如 hh:mm-hh:mm (闭区间),这是一种时间格式,hh:mm 的范围为 00:00 到 23:59。注意一下,时间段是保证不重叠的,但是可能出现跨夜的新番,即新番的开始时间点大于结束时间点。
保证每个时间段的开始时间点和结束时间点不一样,即不可能出现类似 08:00-08:00 这种的时间段。时长的计算由于是闭区间所以也是有点坑的,比如 12:00-13:59 的时长就是 120 分钟。
不保证输入的新番时间表有序。

Output
我们知道,时间管理是一项很难的活,所以你可能没有办法安排的那么好,使得这个时间段满足喵喵的要求,即每次睡必须时间连续且不少于 A 小时,每次醒必须时间连续且不大于 B 小时,还要能看完所有的番,所以输出的第一行是 Yes 或者 No,代表是否存在满足猫猫要求的时间管理办法。
然后,对于时间管理,你只要告诉喵喵,它什么时候睡觉即可。
即第2行输出一个整数 k,代表当天有多少个时间段要睡觉
接下来 k 行是喵喵的睡觉时间段,每行一个时间段,格式形如 hh:mm-hh:mm (闭区间),这个在前面也有定义。注意一下,如果喵喵的睡眠时段跨越当天到达了明天,比如从23点50分睡到0点40分,那就输出23:50-00:40,如果从今晚23:50睡到明天早上7:30,那就输出23:50-07:30。
输出要排序吗?(输出打乱是能过的,也就是说,题目对输出的那些时间段间的顺序是没有要求的)
哦对了,喵喵告诉你说,本题是 Special Judge,如果你的输出答案和 Sample 不太一样,也可能是对的,它有一个判题程序来判定你的答案(当然,你对你自己的答案肯定也能肉眼判断)

Sample Input
12 12 1
23:00-01:00
3 4 3
07:00-08:00
11:00-11:09
19:00-19:59

Sample Output
Yes
1
01:07-22:13
No

2.思路:这个题目简单来说就是个区间检查问题,首先依次输入多个区间,然后我们再查看各个新生成的区间和原区间的情况,输出满足条件的区间。区间的输入好解决,输入之后按照时间大小先后排序即可。唯一需要注意的地方就是这应该是一个环,所以我直接将最小的时间点插入到排好序的数组中。
接下来就是检查各个区间的情况,在输入时,我将区间的起点记为1,终点记为0。所以我们每一次遍历都需要从值为1的结点开始。然后检查区间的时长,如果时长大于所允许的最大值,那么就说明无法完成编排;
还有就是清醒区间时长的计算可能不止一个区间,有可能是多个区间的和,因此我们每一次统计都需要统计到第一个可以睡觉的区间(一旦遇到,将之前的统计结果清零即可)。除此之外,就是需要注意环的问题,遍历到结尾时有可能要回到开头的。

3.代码:

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

struct time
{
	int a, b, c;
	time(int x, int y, int status)
	{
		a = x, b = y, c = status;
	}
	time(){}
	bool operator <(const time& t) const
	{
		if(a!=t.a)
			return a<t.a;
		else if(b!=t.b)
			return b<t.b;
	}
};

bool gettime(time l, time r, int n)
{
	l.b += l.a*60;
	r.b += r.a*60;
	if(r.b<l.b)
		r.b += 24*60;
	if(r.b-l.b-1>=60*n)
		return true;
	return false;
}
int getsum(time l, time r)
{
	if(r.a<l.a)
		r.a +=24;
	r.b += (r.a - l.a)*60;
	return r.b-l.b+1;
}

vector<time> t, sleep; 

int main()
{
	int a, b, n, x, y, sum, status, l;
	while(~scanf("%d %d %d", &a, &b, &n))
	{
		t.clear(), sleep.clear();
		status = 0;
		for(int i=0;i<n;i++)
		{
			scanf("%d:%d-", &x, &y);
			time t1(x, y, 1);
			t.push_back(t1);
			scanf("%d:%d", &x, &y);
			time t2(x, y, 0);
			t.push_back(t2); 
		}
		sort(t.begin(), t.end());
		t.push_back(t[0]);
		sum = 0;	
		for(int i=0;i<t.size();i++) 
		{
			if(t[i].c&&i!=t.size()-1)
			{
				sum +=getsum(t[i], t[i+1]); 
				if(sum>b*60)
					status = 1;	
				i++;
				if(i+1==t.size())
					l = 1;
				else
					l = i+1;
				if(!gettime(t[i], t[l], a))
					sum += getsum(t[i], t[l])-2;
				else
				{
					sum = 0;
					if(t[i].b==59)
					{
						time t1(t[i].a+1, 0, 1);
						sleep.push_back(t1);
					}	
					else
					{
						time t1(t[i].a, t[i].b+1, 1);
						sleep.push_back(t1);
					}	
					if(t[l].b==0)
					{
						time t2(t[l].a-1, 59, 0);
						if(t2.a<0)
							t2.a=23;
						sleep.push_back(t2);
					}		
					else
					{
						time t2(t[l].a, t[l].b-1, 0);
						sleep.push_back(t2);
					}
				}
			}
		}
		if(status||sleep.size()==0)
			printf("No\n");
		else
		{
			printf("Yes\n");
			printf("%d\n", (sleep.size()+1)/2);
			for(int i=0;i<sleep.size();i++)
			{
				printf("%02d:%02d-%02d:%02d\n", sleep[i].a, sleep[i].b, sleep[i+1].a, sleep[i+1].b);
				i++;
			}
		}	
	}
}

Week10-东东转魔方
1.题意:东东有一个二阶魔方,即2×2×2的一个立方体组。立方体由八个角组成。
魔方的每一块都用三维坐标(h, k, l)标记,其中h, k, l∈{0,1}。六个面的每一个都有四个小面,每个小面都有一个正整数。
对于每一步,东东可以选择一个特定的面,并把此面顺时针或逆时针转90度。
请你判断,是否东东可以在一个步骤还原这个魔方(每个面没有异色)。

Input
输入的第一行包含一个整数N(N≤30),这是测试用例的数量。
对于每个测试用例, 第 1~4 个数描述魔方的顶面,这是常见的2×2面,由(0,0,1),(0,1,1),(1,0,1),(1,1,1)标记。四个整数对应于上述部分。
第 5~8 个数描述前面,即(1,0,1),(1,1,1),(1,0,0),(1,1,0)的公共面。四个整数 与上述各部分相对应。
第 9~12 个数描述底面,即(1,0,0),(1,1,0),(0,0,0),(0,1,0)的公共面。四个整数与上述各部分相对应。
第 13~16 个数描述背面,即(0,0,0),(0,1,0),(0,0,1),(0,1),(0,1,1)的公共面。四个整数与上述各部分相对应。
第 17~20 个数描述左面,即(0,0,0),(0,0,1),(1,0,0),(1,0,1)的公共面。给出四个整数与上述各部分相对应。
第 21~24 个数描述了右面,即(0,1,1),(0,1,0),(1,1,1),(1,1,0)的公共面。给出四个整数与上述各部分相对应。
换句话说,每个测试用例包含24个整数a、b、c到x。你可以展开表面以获得平面图

Output
对于每个测试用例,魔方如果可以至多 “只转一步” 恢复,输出YES,则输出NO。

2.思路:本题需要在开始考虑好解题框架,否则会带来一些不必要的麻烦。由题意知,本题的魔方是一个二阶,即222的立方体组,故转的方法有:上面顺时针转90度,前面顺时针,前面逆时针,左边顺时针(相当于右边顺时针),左边逆时针(相当于左边逆时针),逆时针转,分别对不同的情况进行处理,最后按要求输出结果即可。

3.代码:

#include
using namespace std;

int a[7][5],b[7][5];

void way1()   //前面逆时针 
{
	int temp1,temp2;
	temp1=a[6][3];
	temp2=a[6][4];
	a[6][3]=a[1][3];
	a[6][4]=a[1][4];
	a[1][3]=a[5][3];
	a[1][4]=a[5][4];
	a[5][3]=a[3][2];
	a[5][4]=a[3][1];
	a[3][1]=temp2;
	a[3][2]=temp1; 
}

void way2()    //前面逆时针
{
	int temp1,temp2;
	temp1=a[5][3];
	temp2=a[5][4];
	a[5][3]=a[1][3];
	a[5][4]=a[1][4];
	a[1][3]=a[6][3];
	a[1][4]=a[6][4];
	a[6][3]=a[3][2];
	a[6][4]=a[3][1];
	a[3][1]=temp2;
	a[3][2]=temp1; 
}

void way3()   //上面顺时针 
{
	int temp1,temp2;
	temp1=a[2][1];
	temp2=a[2][2];
	a[2][1]=a[6][3];
	a[2][2]=a[6][1];
	a[6][3]=a[4][4];
	a[6][1]=a[4][3];
	a[4][4]=a[5][2];
	a[4][3]=a[5][4];
	a[5][2]=temp1;
	a[5][4]=temp2;
} 
 
void way4()    //上面逆时针
{
	int temp1,temp2;
	temp1=a[2][1];
	temp2=a[2][2];
	a[2][1]=a[5][2];
	a[2][2]=a[5][4];
	a[5][2]=a[4][4];
	a[5][4]=a[4][3];
	a[4][4]=a[6][3];
	a[4][3]=a[6][1];
	a[6][1]=temp2;
	a[6][3]=temp1; 
}

void way5()    //左边顺时针
{
	int temp1,temp2;
	temp1=a[1][1];
	temp2=a[1][3];
	a[1][1]=a[4][1];
	a[1][3]=a[4][3];
	a[4][1]=a[3][1];
	a[4][3]=a[3][3];
	a[3][1]=a[2][1];
	a[3][3]=a[2][3];
	a[2][1]=temp1;
	a[2][3]=temp2; 
} 

void way6()   //左边逆时针
{
	int temp1,temp2;
	temp1=a[1][1];
	temp2=a[1][3];
	a[1][1]=a[2][1];
	a[1][3]=a[2][3];
	a[2][1]=a[3][1];
	a[2][3]=a[3][3];
	a[3][1]=a[4][1];
	a[3][3]=a[4][3];
	a[4][1]=temp1;
	a[4][3]=temp2; 
}

bool judge()
{
	
	int j=0;
	for(int i=1;i<=6;i++)
	{
		if(a[i][1]==a[i][2]&&a[i][2]==a[i][3]&&a[i][3]==a[i][4])
		    j++;
	}
	if(j==6)
	  return true;
	else
	   return false;
}

int main()
{
	int n;
    cin>>n;
    while(n--)
    {
    	for(int i=1;i<=6;i++)
    	{
    		for(int j=1;j<=4;j++)
    		    {
    		    	cin>>a[i][j];
    		    	b[i][j]=a[i][j];
				}
		} 
		if(judge())
		{
			cout<<"YES"<<endl;
			continue;
		}
		way1();
		if(judge())
		{
			cout<<"YES"<<endl;
			continue;
		}
		for(int i=1;i<=6;i++)
    	{
    		for(int j=1;j<=4;j++)
    		    	a[i][j]=b[i][j];
		}
		way2();
			if(judge())
		{
			cout<<"YES"<<endl;
			continue;
		}
		for(int i=1;i<=6;i++)
    	{
    		for(int j=1;j<=4;j++)
    		    	a[i][j]=b[i][j];
		}
		way3();
			if(judge())
		{
			cout<<"YES"<<endl;
			continue;
		}
		for(int i=1;i<=6;i++)
    	{
    		for(int j=1;j<=4;j++)
    		    	a[i][j]=b[i][j];
		}
		way4();
			if(judge())
		{
			cout<<"YES"<<endl;
			continue;
		}
		for(int i=1;i<=6;i++)
    	{
    		for(int j=1;j<=4;j++)
    		    	a[i][j]=b[i][j];
		}
		way5();
			if(judge())
		{
			cout<<"YES"<<endl;
			continue;
		}
		for(int i=1;i<=6;i++)
    	{
    		for(int j=1;j<=4;j++)
    		    	a[i][j]=b[i][j];
		}
		way6();
		if(judge())
		{
			cout<<"YES"<<endl;
			continue;
		}
			for(int i=1;i<=6;i++)
    	{
    		for(int j=1;j<=4;j++)
    		    	a[i][j]=b[i][j];
		}
		cout<<"NO"<<endl;
	}
	return 0;
 }

你可能感兴趣的:(作业Week9、10+月模拟题3、4+CSP3、4+限时大模拟10、14)