CF ROUND#551

第一题,A到车站时间t,有n辆车来,他会再到车站后乘坐第一辆车出发,求是那一辆车。
水题,没有什么说的。

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
typedef pair<int, int> pir;
int n, t;
struct bus {
	int ar, bt;
}buss[105];
int use[105];
int d[105];
int main()
{
	cin >> n >> t;
	upd(i, 1, n)
	{
		cin >> buss[i].ar >> buss[i].bt;
	}
	
	upd(i, 1, n)
	{
		if (buss[i].ar >= t)
		{
			d[i] = buss[i].ar;
		}
		else
		{
			int temp = 0;
			int t1 = t - buss[i].ar;
			if (t1%buss[i].bt == 0)temp = t1 / buss[i].bt;
			else temp = t1 / buss[i].bt + 1;
			d[i] = buss[i].ar + buss[i].bt*temp;
		}
	}
	int MIN = 1e9;
	int ans = 0;
	upd(i, 1, n)
	{
		//cout << d[i] << endl;
		if (MIN > d[i])
		{
			MIN = d[i];
			ans = i;
		}
	}
	cout << ans << endl;
	return 0;
}

第二题,贪心算法。
我们知道三视图后,对于每一块(i,j),我们取min(正,测),贪心变成最高最低。
这样做是一定可以的,因为都是最低最高,不会超过哪一个侧视图或者正试图,同时也满足了两种观察方式得到的最大值

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
typedef pair<int, int> pir;
int main()
{
	int n, m, h;
	int ft[105];
	int lf[105];
	int grp[105][105];
	cin >> n >> m >> h;
	up(i, 0, m)
	{
		cin >> ft[i];
	}
	up(i, 0, n)
		cin >> lf[i];
	up(i, 0, n)
	{
		up(j, 0, m)
		{
			cin >> grp[i][j];
		}
	}
	int res[105][105];
	memset(res, 0, sizeof(res));
	up(i, 0, n)
	{
		up(j, 0, m)
		{
			if (grp[i][j])
			{
				res[i][j] = min(ft[j], lf[i]);
			}
		}
	}
	up(i, 0, n)
	{
		up(j, 0, m)

		{
			printf("%d%c", res[i][j], j == m-1 ? '\n' : ' ');
		}
	}
	return 0;
}

第三题,模拟题目。和HDU上有道题很类似,拿到题目是说,给出(???这种形式,判断有多少种解法。
这里我们依然用贪心来进行模拟。
对于每一个string,我们要让他所有前缀不成为合法字符串,然后他自己本身成为合法的字符串。

所以我们可以尽力让左括号去匹配,尽量多的左括号在左边,因为左右括号相当于1和-1的关系,1越多,-1越难去消掉1使得sum==0,可以想一想sum=0肯定就是合法字符串了啊。
所以我们这里贪心的选取?使得他变成(。实在不行了,再让他变成)。
可以知道如果这种最贪心的方法都不行的话,那么一定没有可行解了。

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
typedef pair<int, int> pir;
char s[300005];
int n;
void unhy()
{
	cout << ":(" << endl; return;
}
int main()
{
	cin >> n;
	int lf = 0, rt = 0;
	int qu = 0;
	if (n & 1) { unhy(); return 0; }
	up(i, 0, n)
	{
		cin >> s[i];
		if (s[i] == '(')lf++;
		else if (s[i] == ')')rt++;
	}
	if (lf > n / 2 || rt > n/2)
	{
		unhy();
		return 0;
	}
	int tlf = n / 2 - lf;//剩余量
	int trt = n / 2 - rt;
	up(i, 0, n)
	{
		if (s[i] == '?') {
			s[i] = '(';
			tlf--;
		}
		if (tlf == 0)break;//贪心匹配完成
	}
	up(i, 0, n)
	{
		if (s[i] == '?')s[i] = ')';//剩下的用做右括号
	}
	bool flag = false;
	int temp = 0;
	int st = 0;
	up(i, 0, n)
	{
		if (st == 0)
		{
			if (s[i] == '(')temp++;
			else temp--;
			st++; 
		}
		else {
			if (temp <= 0) { flag = true; break; }//这里先进行判断才行防止最后一位出错
			if (s[i] == '(')temp++;
			else temp--;
		}
		
	}
	if (temp != 0||flag)unhy();//两种情况
	else
	{
		cout << s << endl;
	}
	return 0;
}

题解看了半天,看不懂,重新思考了很久。。
我们这里定义dp数组,dp[i]表示节点i,取的是,叶子节点中第i大的数。
对于min来说,取得是最小的,所以是i的叶子节点dp的累加和,相当于取叶子节点中最小的那个,即第sum个小。
而对于max来说,取叶子节点中最小的那个,越小说明是第k大,就越大。
所以就能更新出根节点的大小,到底是叶子节点中的的第几大。
这道题得思路就是,因为大小与叶子节点有关,我们从叶子节点开始向上更新,我们不知道叶子节点究竟是排多少,但是我们知道对于每一个有孩子的节点来说,它取哪一个叶子节点是可以更新出来的。所以就这样一直更新上去就能知道,根节点究竟能够取到第几大。
而答案从叶子节点而来,所以我们定义dpi是节点i叶子节点的的第几大。就刚好能够对应上。
相当于变形的树形dp和思维题目。还是有难度的。
初始化每个叶子节点为1。

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
typedef pair<int, int> pir;
const int N = 3 * 100000 + 5;
int a[N];
vector<int >v[N];
int n;
int cnt = 0;
int dp[N];
void  dfs(int i)
{
	if (v[i].size() == 0)
	{
		cnt++;
		dp[i] = 1;
		return;
	}
	dp[i] = a[i] ? N : 0;
	up(j, 0, v[i].size())
	{
		int y = v[i][j];
		dfs(y);
		//cout << "y" << y << dp[y]<<endl;
		if (a[i])dp[i] = min(dp[i], dp[y]);//取max
		else dp[i] += dp[y];//取min
	}
}
int main()
{
	cin >> n;
	upd(i, 1, n)
	{
		scanf("%d", &a[i]);
	}
	int temp;
	upd(i, 2, n)
	{
		scanf("%d", &temp);
		v[temp].push_back(i);

	}//建树。
	dfs(1);
	/*upd(i, 1, n)
	{
		cout << "i" << i << dp[i] << endl;
	}*/
	cout << cnt + 1 - dp[1]<<endl;//节点是叶子中第几大
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44019404/article/details/89321429
今日推荐