首页 > 其他分享 >CF1737C Ela and Crickets 题解

CF1737C Ela and Crickets 题解

时间:2024-04-10 21:44:26浏览次数:26  
标签:p2 p1 target 题解 Ela Crickets chess max cr

题面

原先大佬的题解写的很好,但这里想讲一下不同做法。

思路

题目中说的 \(L\) 型有四种情况,很容易就可以想到特殊情况,那就是 \(L\) 型恰好贴在棋盘的四个角上,这时我们发现,这样子棋子只能在棋盘的其中两条边上移动。对于四个角我们进行四次特判。

看普通情况,在手动模拟完样例后发现,棋盘上到不了的点是有一定的规律,换个想法理解,棋盘上能够到达的所有点都可看做是原 \(L\) 型的三个点沿着 \(r\) 或 \(c\) 平移 \(2k\) 个单位长度,其中 \(k\) 为整数。这个时候我们不用理会部分出界的情况,只要有一部分仍在棋盘内,原来的 \(L\) 型就可以移动到那里。

看回 \(L\) 型,把它补成一个 \(2 \times 2\) 的正方形,再结合上面的话,就会发现,那些永远达不到的点,就是那个被补上去的点。这时只要看目标点是否在这些点之间就行了。

代码实现

思路好想,但是代码还是有很多小细节。

首先是对最开始三个棋子位置的记录及特判,如果一个一个判断,将要花费巨大的时间与精力。所以最好的方法是运用数组。

一开始我想开一个 \(10^5 \times 10^5\) 的二维数组,但感觉会空超,于是就变成了这样:

struct edge
{
    bitset<100005> r;
}c[100005];

可实际上,该超还是超,直到我看见了这样的一个东西:map。我只需要记录四个角是否有对应的棋子,并不需要知道具体是哪个棋子,map 正好满足我的需要。只要在用完后将用的位置清零就解决了。

其次是如何判断目标点是否在 \(L\) 型永远到不了的点上。直接分四种情况讨论太复杂了,所以需要找到一点规律。设三个棋子分别为 \(chess_1\),\(chess_2\),\(chess_3\),\(L\) 型的拐角点为 \(chess_2\)。发现,其中一个到不了的点一定在 \(L\) 型拐角点左下角 \((r_2 - 1,c_2 - 1)\) 的位置上。那么如何表示出这个点呢?

结论

设这个点的位置为 \((r_a,c_a)\),则满足 \(r_a=r_1+r_2+r_3-2 \times \max(r_1,r_2,r_3)\),\(c_a=c_c+c_2+c_3-2 \times \max(c_1,c_2,c_3)\)。

证明

这两个结论的证明类似,所以这里给出 \(r_a\) 的证明过程。

设 \(r_x=\max(r_1,r_2,r_3)\),\(r_n=\min(r_1,r_2,r_3)\)。由于 \(L\) 型是三个相连的棋子,所以满足 \(r_x-r_n=1\)。对于四种 \(L\) 型可以进行归类。

两个棋子在上,一个棋子在下

包括

\(chess_1\) \(chess_2\)
\(chess_3\)

以及

\(chess_2\) \(chess_1\)
\(chess_3\)

两种情况。

此时可以发现 \(r_1=r_2=r_x\),\(r_3=r_n\)。而 \(r_a=r_x-1\)。
我们对 \(r_a=r_x-1\) 进行变形。

\(r_a=r_x-1\),

将 \(1\) 用 \(r_x-r_n\) 代替,

\(r_a=r_x-(r_x-r_n)\),

去括号,

\(r_a=r_x-r_x+r_n\),

在后面加上 \(r_x\) 然后再减去,这一步其实非常玄乎,一开始我并没有想到这么写,直到将另外一种情况讨论完后才悟到可以这么写,可以看做纯数字做法。

\(r_a=r_x-r_x+r_n+r_x-r_x\),

移项,部分合并,

\(r_a=r_x+r_x+r_n-2 \times r_x\),

而前面已知 \(r_1=r_2=r_x\),\(r_3=r_n\),\(r_x=\max(r_1,r_2,r_3)\),所以 \(r_a=r_1+r_2+r_3-2 \times \max(r_1,r_2,r_3)\)。

两个棋子在下,一个棋子在上

包括

\(chess_1\)
\(chess_2\) \(chess_3\)

以及

\(chess_1\)
\(chess_3\) \(chess_2\)

两种情况。

此时可以发现 \(r_1=r_x\),\(r_2=r_3=r_n\)。而 \(r_a=r_x-2\)。
我们对 \(r_a=r_x-2\) 进行变形。

\(r_a=r_x-2\),

将 \(2\) 用 \(r_x-r_n\) 代替,

\(r_a=r_x-2 \times (r_x-r_n)\),

去括号,

\(r_a=r_x-2 \times r_x+2\times r_n\),

拆项,

\(r_a=r_x-r_x-r_x+r_n+r_n\),

移项,部分合并,

\(r_a=r_x+r_n+r_n-2 \times r_x\),

而前面已知 \(r_1=r_x\),\(r_2=r_3=r_n\),\(r_x=\max(r_1,r_2,r_3)\),所以 \(r_a=r_1+r_2+r_3-2 \times \max(r_1,r_2,r_3)\)。


化简完后发现四种情况的 \(r_a\) 都可以用同一个式子表示出来。

那又该如何判断题目给出的目标点是否在不可到达的点上呢?

由于不可到达的点也是由 \((r_a,c_a)\) 沿着 \(r\) 或 \(c\) 移动 \(2k\) 个单位得到的,其中 \(k\) 为整数,所以只需要像下面的代码一样判断是否横纵坐标之和或差是否是二的倍数就好了。

			ll mid_r = p1.r + p2.r + p3.r - 2 * max(p1.r , max(p2.r , p3.r));
            ll mid_c = p1.c + p2.c + p3.c - 2 * max(p1.c , max(p2.c , p3.c));
            if((mid_r + target.r) % 2 == 0 && (mid_c + target.c) % 2 == 0)
            {
                printf("NO\n");
                continue;
            }
            else
            {
                printf("YES\n");
                continue;
            }

其中 mid_r 便是刚才的 \(r_a\),mid_c 就是 \(c_a\)。\(target\) 是用结构体定义的,表示目标点及其横纵坐标。

代码

#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cstring>
#include<algorithm>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#define ll long long
#define ld double
#define inf 0x3f3f3f3f
#define fr(i , a , b) for(ll i = a ; i <= b ; ++i)
#define fo(i , a , b) for(ll i = a ; i >= b ; --i)
#pragma comment(linker , "/stack : 200000000")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
using namespace std;
inline char gchar()
{
    static char buf[1000000] , *p1 = buf , *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf , 1 , 1000000 , stdin) , p1 == p2) ? EOF : *p1++;
}
inline ll read()
{
    ll x = 0 , f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
	  {
        if(ch == '-')
        {
        	f = -1;
		}
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
	  {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
ll t , n;
struct node
{
    ll r , c;
}p1 , p2 , p3 , target;
signed main()
{
    t = read();
    while(t--)
    {
        map<pair<ll , ll> , ll> cr;
        n = read();
        cr[{p1.c , p1.r}] = 0;
        cr[{p2.c , p2.r}] = 0;
        cr[{p3.c , p3.r}] = 0;
        p1.r = read();
        p1.c = read();
        cr[{p1.c , p1.r}] = 1;
        p2.r = read();
        p2.c = read();
        cr[{p2.c , p2.r}] = 1;
        p3.r = read();
        p3.c = read();
        cr[{p3.c , p3.r}] = 1;
        target.r = read();
        target.c = read();
        if(cr[{1 , 1}] && cr[{1 , 2}] && cr[{2 , 1}])//左下角特判
        {
            if(target.c == 1 || target.r == 1)
            {
                printf("YES\n");
                continue;
            }
            else
            {
                printf("NO\n");
                continue;
            }
        }
        else if(cr[{1 , n}] && cr[{1 , n - 1}] && cr[{2 , n}])//左上角
        {
            if(target.c == 1 || target.r == n)
            {
                printf("YES\n");
                continue;
            }
            else
            {
                printf("NO\n");
                continue;
            }
        }
        else if(cr[{n , 1}] && cr[{n - 1 , 1}] && cr[{n , 2}])//右下角
        {
            if(target.c == n || target.r == 1)
            {
                printf("YES\n");
                continue;
            }
            else
            {
                printf("NO\n");
                continue;
            }
        }
        else if(cr[{n , n}] && cr[{n - 1 , n}] && cr[{n , n - 1}])//右上角
        {
            if(target.c == n || target.r == n)
            {
                printf("YES\n");
                continue;
            }
            else
            {
                printf("NO\n");
                continue;
            }
        }
        else
        {
            ll mid_r = p1.r + p2.r + p3.r - 2 * max(p1.r , max(p2.r , p3.r));
            ll mid_c = p1.c + p2.c + p3.c - 2 * max(p1.c , max(p2.c , p3.c));
            if((mid_r + target.r) % 2 == 0 && (mid_c + target.c) % 2 == 0)
            {
                printf("NO\n");
                continue;
            }
            else
            {
                printf("YES\n");
                continue;
            }
        }
    }
    system("pause");
    return 0;
}

标签:p2,p1,target,题解,Ela,Crickets,chess,max,cr
From: https://www.cnblogs.com/xhqdmmz/p/18127553

相关文章

  • CF1162B Double Matrix 题解
    传送门说句实话,如果不是先写了Showstopper这道题的话,我应该会在这里卡很久,因为做Showstopper我就卡了很久QwQ。思路太像了,实在是太像了,与Showstopper想比,仅仅就是换成二维数组,求最大值变为找递增矩阵,处理方法一模一样:将数组\(a\)和\(b\)中较小的值存在一个数组里,较......
  • 【华为笔试题汇总】2024-04-10-华为春招笔试题-三语言题解(Python/Java/Cpp)
    ......
  • 关于淘宝镜像过期问题解决方案
    问题:将项目拷贝到另一台电脑启动时报错Error:Theprojectseemstorequireyarnbutit'snotinstalled解决方法:1.删除项目中的yarn.lock文件2.终端执行npminstall-gyarn再次启动项目npmrunserve就可以了......
  • Codeforces Round 938 (Div. 3) A-H 题解
    A-YogurtSaleSolution当\(2a>b\)时,显然用\(a\)来买两个比较好,否则就用\(b\)来买两个比较好Code#include<bits/stdc++.h>usingnamespacestd;voidsolve(){intn;cin>>n;inta,b;cin>>a>>b;b=min(b,a*2);int......
  • AT_agc038_e [AGC038E] Gachapon 题解
    比较基础的一道题。很容易想到Min-Max容斥:\[E(\max(S))=\sum_{T\subeS}(-1)^{|T|-1}\timesE(\min(T))\]然后发现\(E(\min(T))=\sum_{k\ge0}P(\min(T)\gek)\)。考虑dp,记\(f_{i,j,k}\)表示从前\(i\)个数中选出\(T\),\(\sum_{i\inT}A_i=j,\sum_{i\inT}c_i=k\)且每个......
  • MHY1001. [崩三]椰子树题解
    #include<bits/stdc++.h>usingnamespacestd;constintN=1010,M=20010;intq[M];//s的最大值为20000,v的最小值为1,所以队列里面最多是会有200010个元素的intn,m;intf[M],g[M];intmain(){cin>>n>>m;for(inti=1;i<=n;++i){......
  • CF1804C Pull Your Luck 题解
    题面。翻译清晰,这里就不吐槽了。根据轮盘转动的方法,可以看出这是一个简单的高斯求和。因为这是一个轮盘,在轮盘中转动了\(now\)个格子与转动了\(now\bmodn\)所到达的格子是一样的(这就没必要证明了吧),因此我们很容易就能得到一个最朴素的代码: cin>>T; while(T--) { c......
  • P3891 [GDOI2014] 采集资源 题解
    题面。看到大家都是两个动态规划的写法,来给大家讲一下只用一次动态规划的写法。思路设\(f_{i,j}\)表示工作效率为\(i\),获取\(j\)点资源所需的最短时间,不以苦工设状态是因为苦工会因为后面购买而改变,不太现实。\(tme\)表示答案,即到达\(t\)点资源所需的最短时间。从\(0......
  • P8661 [蓝桥杯 2018 省 B] 日志统计 题解
    好久没写题解了,水一篇。这里主要想讲的是不同的处理方法,在阅读本篇题解前请确保读完题。详解一,排序这很好理解,题目要求将热帖从小到大输出,同时题目中还有相对的时间这一概念,因此将输入的\(id\)与\(ts\)按照优先\(id\)其次\(ts\)的排序方式从小到大,排序,这样输出时就没......
  • CF133B Unary 题解
    题面。在考虑如何优化程序时,不要忽略了这题的纯暴力做法。对于样例2此处样例2的输入应该是++++[>,.<-],也许是翻译问题,但并不重要。思路依据题意,将输入的字符串\(s\)转为其对应的二进制串\(str\),在暴力将\(str\)由二进制转为十进制即可。代码为了防止因为幂运算而......