NZOJ 模拟赛4

T1 数字游戏

大家列队后,都觉得累了,于是一起坐到院子中的草地上休息。这时Anna突然想跟她的最大竞争对手Cici玩一个数字游戏,她要你编写程序帮助她取得胜利。

第i次游戏初始时有一个整数N_i(1 <= N_i <= 1,000,000),游戏以Anna先开始,然后是Cici,这样两人轮流进行。在每一轮中,一个游戏者可以把当前整数中减去原整数中最大的数字或最小的非零数字,形成一个新的整数。例如从3014开始,我们可以减去1或4,分别形成整数3013或3010.直到这个整数变为0时游戏结束。游戏结束时最后轮到那人就是胜利者。

Anna和Cici总共进行G(1 <= G <= 100)次游戏。请你帮助确定每次游戏到底是Anna还是Cici获得胜利。Anna和Cici两人都是足够聪明的,如果轮到某人时,对方留给她的数是必胜的,她将毫不犹豫按最优策略取得胜利。

假如某次游戏N_i=13。Anna先走并从中减去3,剩下10,然后Cici只能减去1,剩下9,Anna减去9,剩下0游戏结束,Anna取得这次游戏的胜利。

考察对SG函数的运用,为所有后继节点权值的 \(Mex\) 和,如果 \(SG[x] ~ = ~ 0\) 则必败,否则必胜。

参考代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int sg[N];

int check(int x)
{
	if (sg[x] != -1) return sg[x];
	int maxx = 0, minn = 9, k = x;
	while (k)
	{
		int t = k % 10;
		k /= 10;
		if (t) maxx = max(t, maxx), minn = min(t, minn);
	}
	unordered_set<int> S;
	S.insert(check(x - maxx));
	S.insert(check(x - minn));
	for (int i = 0; ; i ++ )
		if (!S.count(i))
			return sg[x] = i;
}

void solve()
{
	int n;
	cin >> n;
	check(n) ? puts("YES") : puts("NO");
}

int main()
{
	memset(sg, -1, sizeof sg);
	sg[0] = 0;
	int T;
	cin >> T;
	while (T -- ) solve();
} 

T2 电话时间(phone)

某人总是花很多时间给父母打电话。有一次他记录了打电话的开始时间和结束时刻t1和t2,请你帮他算算此次通话一共用了多少秒。又有一次,他记录了打电话的开始时刻t1和通话的时间长度len,请你帮他计算他在什么时刻结束通话。
已知每次通话时间小于24个小时。

小模拟,按照题目要求模拟即可。

T3 开心农场

Chroi整个暑假忙于OI,没什么时间照顾开心农场,需要你的帮助。他可以告诉你他哪些时间上线,你要做的就是告诉他最多可赚多少钱。而且由于Chroi的农场等级比较低,所以只能种单季作物,就是只能收获一次的。
在开心农场中,每个用户都有一定数目的土地,每次上线可以做的事是在土地上摘果实、卖果实、种下种子,每块土地上只能种一种作物,每块土地各自独立。
假设Chroi每次上线的时长是一瞬间,他能在瞬间做完所有他想做的事。

输入文件包含多行,第一行有三个正整数n,m,t,k,分别表示Chroi的农场中有n块地,共有m种作物可以选择,一天有t个时刻,有k个时刻Chroi可以上线。
接下来的m行每行输入三个正整数,第一个数字表示种子价格,第二个数字表示种子成熟时间(小于t),第三个数字表示成熟后果实的售价。再次提示,这些都是整数。
再接下来的一行有k个自然数,保证该整数为0,1,2...t-1中的一个,为Chroi可以上线的时刻。这k个自然数不会重复。
输入文件到此结束。

首先很自然的一个想法是,这么多地,如果种植了某种作物,又种植的其他作物,那么只种价值最高的那种作物一定是最优的。

第二个想法是,如果有两种作物种植时间相等,那么选择最划算的那个一定最优。

然后考虑如何dp,很直接的想法是按照时间dp,对于当前时间节点 \(dp[i]\),如果存在一个时间节点 \(dp[j](j < i)\),Chroi恰好能在 \(i, ~ j\) 这两个时刻都上线,那么可以列出状态转移方程 \(dp[i] = dp[j] + w\)\(w\) 表示能种植在这段区间的作物,利用一个前缀 \(max\) 数组存储最优 \(w\),每次合法时考虑种植最优的即可。

参考代码


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3010;
int n, m, t, k, st[N];
ll w[N], dp[N], maxx[N];

int main()
{
	cin >> n >> m >> t >> k;
	for (int i = 1; i <= m; i ++ )
	{
		ll a, b, c;
		cin >> a >> b >> c;
		w[b] = max(w[b], c - a);
	}
	for (int i = 1; i < t; i ++ ) maxx[i] = max(maxx[i - 1], w[i]);
	for (int i = 1; i <= k; i ++ )
	{
		int a;
		cin >> a;
		st[a] = 1;
	}
	for (int i = 0; i < t; i ++ )
		for (int j = 0; j < i; j ++ )
			if (st[i] && st[j])
				dp[i] = max(dp[j] + maxx[i - j] * n, dp[i]);
	ll ans = 0;
	for (int i = 0; i < t; i ++ ) ans = max(ans, dp[i]);
	cout << ans << endl;
	return 0;
}

T4 选票统计

有k名候选者,有n(n<=10000)人参加了投票,与以往不同的是,这次所有得票数超过n/4的人都是优胜者。请你统计收到的n张选票,找出符合条件的优胜者(可能不止一个)。
第一行一个整数n。
第二行有n个正整数,每个数字代表一张选票所选的人的编号(编号<longint范围)。
每行一个正整数,为优胜者的编号,由小到大,一行一个优胜者的编号。如果没人获胜,则输出“No such person.”。

模拟一下,开一个桶记录票数,扫一遍就是答案。

posted @ 2024-09-30 13:32  YipChip  阅读(33)  评论(0)    收藏  举报