首页 > 其他分享 >Codeforces Round 801 (Div. 2)

Codeforces Round 801 (Div. 2)

时间:2023-12-09 19:57:41浏览次数:36  
标签:std dp2 dp1 int 路径 Codeforces 801 Div dp

基本情况

A就开始犯病,导致+2.

B、C 都过样例了,但是都错。

B. Circle Game

赛时推出来奇数必输,也知道偶数不是必赢,但是思路不清楚。


这里我没意识到一个很关键的性质。

奇数堆拿的石堆会变,这也导致了必输,比如三个堆 \(1,2,3\)。表粗的为JOE。

1 2 3 1 2 3

显然JOE拿的石堆是变化的。

偶数堆拿的石堆不会变

1 2 3 4 1 2 3 4

通过分析,可以发现最小堆的石头(如果存在多个,我们取编号最小的)是第一个被拿完的,这堆石头的主人也必定会输。

那么偶数下直接看看最小堆是谁即可。

#include<iostream>
#include<algorithm>
#include<cstdio>

int a[51];

int main()
{
 	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout.tie(nullptr);
	int _; std::cin >> _;
	while(_--)
	{
		int n, temp, ok = true, minP = 1;
		std::cin >> n;
		for(int i = 1; i <= n; i++) std::cin >> a[i];
		if (n & 1) {std::cout << "Mike" << std::endl; continue;}
		for (int i = 2; i <= n; i++)
		{
			if (a[i] < a[minP]) minP = i;
		}
		if (minP & 1) std::cout << "Joe" << std::endl;
		else std::cout << "Mike" << std::endl;
	}
	return 0;
}

C. Zero Path

我的错解

一眼DP,然后自以为是的写了一个逆天假DP。。。

dp[1][1] = a[1][1];
	dp[n][m] = 0x7fffffff; 
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
		{
			if (i >= 2 && j == 1)
			{
				dp[i][j] = dp[i - 1][j] + a[i][j];continue;
			}
			if (j >= 2 && i == 1)
			{
				dp[i][j] = dp[i][j - 1] + a[i][j];continue;
			}
			if (abs(dp[i][j - 1] + a[i][j]) < abs(dp[i - 1][j] + a[i][j]) )
				dp[i][j] = dp[i][j - 1] + a[i][j];
			else
				dp[i][j] = dp[i - 1][j] + a[i][j];
		}
	std::cout << (dp[n][m] == 0 ? "YES" : "NO") << std::endl;

仔细一想,之前的题目,维护最大值、最小值,是符合DP的要求的,最优子结构,无后效性,虽然我说不明白,但是这题我维护的东西仔细想想并不符合DP的要求,所以这样直接维护是短视的,感觉有点像贪心,反正不是DP。


正确DP

首先,如果经过奇数个格子,或者说 \(n + m - 1\) 为奇数,那么肯定没有这样的一条路径(经过的 \(-1\) 和 \(1\) 点没有办法相等)。

直接判断某个格子图是否符合要求太麻烦,我们可以思考,如果有任意一条路径,我们是否能根据这条路径的值(也就是途径的格子的和),来做一些改变,最后让路径的值变为 \(0\)。

如下图这样就是对路径做了一次改变(改变前后只有一个格子不同)。最后让路径的值产生了变化。
示意图,来自官方题解

在一次改变中,路径的值会产生 \(-2 (-1 \rightarrow 1)\), \(2 (1 \rightarrow -1)\) 或是 \(0 (1 \rightarrow 1 \operatorname{OR} -1 \rightarrow -1)\) 的变化,那么如果我们刚开始的路径值是一个偶数,就可以把这个路径通过这样的改变变为 \(0\) 吗?

显然是不行的,如果整个格点图全是 \(-1\) 或是全是 \(1\) 就不行,所以我们还得做一些改进。

首先就得确保在这个格点图中不会只有值特别离谱的路径,如果只有值特别离谱的路径,那无论你怎么变,也搞不出值为 \(0\) 的路径。

所以我们需要找出值最大的路径,以及值最小的路径。

设值最大的路径的值为 \(p_{\max}\),最小的路径的值为 \(p_{\min}\)。

那么如果:

\[p_{\min} \le 0 \le p_{\max} \]

我们就一定可以通过这样的变化把任意一个值为偶数的路径变为值为 \(0\) 的路径。

或者可以这样理解,如果符合上面那个条件,那我们就可以逐渐把值最小的路径向值最大的路径变换,在这个过程中,一定有一个路径的值等于 \(0\)。

至于求这样的格子图的最大和最小路径,就属于是典中典了。

代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>

const int N = 1e3 + 10;
int n, m;
int a[N][N];
int dp1[N][N], dp2[N][N];

void solve()
{
	std::cin >> n >> m;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++) std::cin >> a[i][j];
	memset(dp2, 0, sizeof(dp2));
	memset(dp1, 0, sizeof(dp1));
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
		{
			if (i >= 2 && j == 1)
			{
				dp1[i][j] = dp1[i - 1][j] + a[i][j]; dp2[i][j] = dp2[i - 1][j] + a[i][j]; 
				continue;
			}
			if (j >= 2 && i == 1)
			{
				dp1[i][j] = dp1[i][j - 1] + a[i][j]; dp2[i][j] = dp2[i][j - 1] + a[i][j]; 
				continue;
			}
			dp1[i][j] = std::max(dp1[i - 1][j], dp1[i][j - 1]) + a[i][j];
			dp2[i][j] = std::min(dp2[i - 1][j], dp2[i][j - 1]) + a[i][j]; 
		}
	if (dp1[n][m] & 1 || dp2[n][m] > 0 || dp1[n][m] < 0) 
	{
        std::cout << "NO\n";
    } 
	else
	{
        std::cout << "YES\n";
    }
} 

int main()
{
 	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout.tie(nullptr);
	int _; std::cin >> _;
	while(_--) solve();
	return 0;
}

标签:std,dp2,dp1,int,路径,Codeforces,801,Div,dp
From: https://www.cnblogs.com/kdlyh/p/17891381.html

相关文章

  • [Codeforces] CF1763B Incinerate
    CF1763BIncinerate题意为了消灭人类,怪物协会向地球表面派出了\(n\)只怪兽。第\(i\)只怪物有一个生命值\(h_i\)和一个攻击力\(p_i\).凭借他最后的一击,真螺旋焚烧炮,Genos可以对所有活着的怪物造成\(k\)点伤害。换句话说,Genos可以通过一次攻击降低所有怪物\(k\)点......
  • Codeforces Round 909 (Div. 3)
    https://codeforces.com/contest/1899  一个小游戏#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>usingnamespacestd;intn;intmain(){cin>>n;while(n--){intx;......
  • [Codeforces] CF1704C Virus
    CF1704CVirus题意有一个长度为\(n\)的环,即对于\(1\leqi\leqn\),满足第\(i\)个与第\(i+1\)个房子相邻,特别地,第\(n\)个房子与第\(1\)个房子也相邻。一开始,这\(n\)个房子中有\(m\)个房子被病毒感染了。在之后的每天早上,都可以选择一个未被感染的房子并对其进行保护,被保......
  • [Codeforces] CF1703E Mirror Grid
    CF1703EMirrorGrid题意给定一个\(n\timesn\(n\le100)\)的01矩形,求至少修改多少次后能使矩形旋转0°,90°,180°,270°后所形成的矩形都完全相同。思路吸纳分为两种情况讨论:\(n\)为奇数那么会出现这种情况:(以\(5\times5\)为例)如上图,我们就可以将其分为五个部分,每个......
  • Codeforces Round 811 (Div. 3)
    基本情况ABC秒了。DE都给了我希望,但都做不下去。两道题反复横跳,结果最后谁也没做出来。E还是比D亲切的,先补E吧。E.AddModulo10做的时候想着说对每个个位数的变化找找规律,但是没有进一步的发现。实际上就应该从这里下手。首先共识:相同的两个数经过操作后必然相同。分析......
  • Codeforces Round 913 (Div. 3)
    A.Rook打印出象棋车的下一步usingnamespacestd;voidsolve(){ strings; cin>>s; chara=s[0]; charb=s[1]; set<string>ans; for(chari='1';i<='8';i++){ stringt=""; t+=a; t+=i; ans.insert(t); } for(chari......
  • 【LGR-168-Div.4】洛谷入门赛 #18
    打表过样例题目描述很不幸,你遇到了不负责任的出题人。在某道试题里,共有\(N\)个测试点,组成了\(k\)个Subtask,第\(i\)个Subtask包含\(p_i\)个测试点,第\(j\)个测试点的编号为\(w_{i,j}\)。请注意,一个测试点可能属于多个Subtask。Subtask每个Subtask包含多个测......
  • 可以拖拽缩放的div
    一、HTML代码<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"/><metahttp-equiv="X-UA-Compatible"content="IE=edge"/><metaname="viewport"content......
  • [ABC254Ex] Multiply or Divide by 2
    [ABC254Ex]MultiplyorDivideby2题意:给定大小为$n$的集合$A$和$B$,你可以对集合$A$中的元素$a_i$进行两种操作,分别为$a_i\leftarrow\lfloor\dfrac{a_i}{2}\rfloor$,和$a_i\leftarrowa_i\times2$。你需要操作集合$A$直至集合$A,B$完......
  • Codeforces Round 894 G
    玩一下样例就能知道这个是和每个seg的最大间隔相关为了好写我们可以直接写成元素间隔这样我们用两个multiset维护元素间隔以及元素即可注意删除的时候我们只删一个值需要删指针还有考虑长度为1的情况multiset<int>st,st1;voidErase(intx){autoit=st1.lower_bound......