Codeforces Round 864 (Div. 2)

文章目录

  • 一、Li Hua and Maze
  • 二、Li Hua and Pattern
  • 三、Li Hua and Chess
  • 四、Li Hua and Tree


一、Li Hua and Maze

  • 思路:
    对于一个点(X,Y)来说,答案最多就是4,也就是(X +1,Y),(X - 1,Y),(X,Y + 1),(X,Y - 1),但是对于边界上面的点,也就是网格的四个角,答案就是2,如果是在除了四个定点的边界上面答案就是3,然后判断一下即可

  • 代码:

#include 
#define ios ios::sync_with_stdio(0),cin.tie(0)
#define fi first
#define se second
#define pb push_back
#define PII pair<int,int>
#define int long long 
using namespace std;

const int N = 2e5 + 100,M = N * 2,INF = 0x3f3f3f3f,mod = 998244353;

void solve()
{
     int n,m,x1,y1,x2,y2; cin >> n >> m >> x1 >> y1 >> x2 >> y2;
     
     if(x1 == 1 && y1 == 1 || x1 == n && y1 == m || x2 == 1 && y2 == 1 || x2 == n && y2 == m) cout << "2" << endl;
     else if(x1 == 1 && y1 == m || x1 == n && y1 == 1 || x2 == 1 && y2 == m || x2 == n && y2 == 1) cout << "2" << endl;
     else if(x1 == 1 || x1 == n || y1 == 1 || y1 == m || x2 == 1 || x2 == n || y2 == 1 || y2 == m) cout << "3" << endl;
     else cout << "4" << endl;
}

signed main()
{
    ios;
    int T = 1;cin >> T; while(T -- ) solve();
    return 0;
}

二、Li Hua and Pattern

  • 思路:

    1: 对于一个正方体想要翻转180度以后和原来的相等,(可以自己试一下)会发现必须满足a[x][y] = a[n - x + 1][n - y + 1],比如n = 2,翻转180,必须满足a[1][1] = a[2][2],a[1][2] = a[2][1]

    2: 如果n是奇数的话,最中间的一个点不需要和谁相等,所以n是奇数的话,多余的k可以一直在这个点进行操作(因为不管翻转多少度,最中间点的位置一定不变)

    3: 进行统计 a[x][y] != a[n - x + 1][n - y + 1] 的情况数量,假设为D,判断 k 与D的关系,
    必须满足k >= D,然后剩余的操作次数就通过n来判断,如果n是奇数,那就让所有的操作都操作在a[n / 2+ 1][n / 2 + 1]这个点,所以一定是YES,如果n是偶数的话,就需要剩余的操作次数也得是偶数,(保证翻转180之后还相等)

  • 代码:

#include 
#define ios ios::sync_with_stdio(0),cin.tie(0)
#define fi first
#define se second
#define pb push_back
#define PII pair<int,int>
#define int long long 
using namespace std;

const int N = 1e3 + 5,M = N * 2,INF = 0x3f3f3f3f,mod = 998244353;
int a[N][N];
// 现在需要思考的是什么样的情况下,可以使得翻转180以后还是跟原来的一样

void solve()
{
     int n,k; cin >> n >> k;
     for(int i = 1;i <= n;i ++ )
        for(int j = 1;j <= n;j ++ )
            cin >> a[i][j];
    int d = 0; // 改变几个
    for(int i = 1;i <= n / 2 + (n % 2 == 1);i ++ )
    {
        
        if(n % 2 == 1 && i ==  n / 2 + 1)
        {
            for(int j = 1;j <= n / 2;j ++ )
             if(a[i][j] != a[n - i + 1][n - j + 1])
             {
                 ++d;
             }
        }
        else
        {
             for(int j = 1;j <= n;j ++ )
        {
             if(a[i][j] != a[n - i + 1][n - j + 1])
             {
                 ++d;
             }
        }
        }
       
    }
    
    if(k >= d)
    {
        k -= d;
        if(n & 1)
        {
             cout << "YES" << endl;
        }
        else
        {
            if(k % 2 != 0) cout << "NO" << endl;
            else 
            {
                cout << "YES" << endl;
            }
        }
    }
    else 
    cout << "NO" << endl;
    
}

signed main()
{
    ios;
    int T = 1;cin >> T; while(T -- ) solve();
    return 0;
}

signed main()
{
	ios;
	int T;cin >> T;
	while(T -- ) solve();
	return 0;
}

三、Li Hua and Chess

  • 思路:
    1: 询问给出的答案一定是 max(abs(x - x1),abs(y - y1));,这个可以通过画图发现出来,所以我们可以先询问(1,1)答案为 k1,那这个点一定是(k1 + 1,?) 或者 (?,k1 + 1)

    2: 再询问(k1 + 1,k1 + 1),答案为k2, k1 + 1 - k2一定是横坐标或者纵坐标(因为从1中知道答案是取最大值,其中一个值一定为0,所以另一个值一定是横坐标或者纵坐标)需要注意的是(k1 + 1,k1 + 1)可能会超出范围,那我们特判一下就好了

    3: 此时就知道这个点要么是(k1 + 1,k1 + 1 - k2) or (k1 +1 - k2,k1 + 1),这时候就再询问(k1 + 1,1)来判断是哪一个点,

  • 代码:

#include
#define PII pair<int,int>
#define fi first
#define se second
#define pb push_back
#define int long long
using namespace std;
const int N = 1e6 + 10,M = 1000007,INF = 1e18 + 1,mod = 1000000007;

int ask(int x,int y)
{
	cout << "? " << x << ' ' << y << endl;
	int k; cin >> k;
	return k;
} 
void print(int a,int b)
{
	cout << "! " << a << ' ' << b << endl;
}

void solve()
{
	int n,m; cin >> n >> m;
	int k1 = ask(1,1);
	if(k1 + 1 > n) // 特判,超过n了,那k1 + 1一定是y
	{
		print(ask(1,k1 + 1) + 1,k1 + 1);
		return;
	}
	if(k1 + 1 > m)// 特判,超过m了,那k1 + 1一定是x
	{
		print(k1 + 1,ask(k1 + 1,1) + 1);
		return;
	}
	
	int k2 = ask(k1 + 1,k1 + 1);
	if(k1 + 1 == k1 + 1 - k2) print(k1 + 1,k1 + 1);
	else
	{
		int k3 = ask(k1 + 1,1);
		if(k3 + 1 == k1 + 1 - k2)print(k1 + 1,k1 + 1 - k2);
		else print(k1 + 1- k2,k1 + 1); 
	}
}

signed main()
{
  ios::sync_with_stdio(false);  cin.tie(0); cout.tie(0);
  int T; T = 1;cin >> T; 
  while(T--) solve();
}

四、Li Hua and Tree

  • 思路:
    暴力模拟就好dfs来获得每个点的重要值长度,用set存每个点的子节点的长度和索引,这个学到的新知识是知道了用set判断结构体,很厉害
  • 代码:
#include
#define PII pair<int,int>
#define fi first
#define se second
#define pb push_back
#define int long long
using namespace std;
const int N = 1e6 + 10,M = 1000007,INF = 1e18 + 1,mod = 1000000007;
int sz[N],sum[N];
vector<int> g[N];
int fa[N],a[N];
 
struct node
{
	int sz,id;
	bool operator <(const node & w) const // 用优先队列的判断与其他的判断是相反的
	{
		if(sz != w.sz) return sz > w.sz; // 优先队列升序是 < ,set什么的就是 >
		return id < w.id;	
	};
};
set<node> s[N]; 

void dfs(int u,int f) // 
{
	sz[u] = 1;
	sum[u] = a[u];
	
	for(auto j : g[u])
	{
		if(j == f) continue;
		fa[j] = u;
		dfs(j,u);
		sz[u] += sz[j];
		sum[u] += sum[j];
		s[u].insert({sz[j],j}); // 存子节点
	}
}

void solve()
{
	int n,m; cin >> n >> m;
	for(int i = 1;i <= n;i ++ ) cin >> a[i];
	for(int i = 1;i < n;i ++ )
	{
		int u,v; cin >> u >> v;
		g[u].pb(v);
		g[v].pb(u);
	}
	
	dfs(1,-1);
	
	while(m -- )
	{
		int op,x;
		cin >> op >> x;
		if(op == 1) 
		cout << sum[x] << endl;
		else
		{
			if(s[x].empty()) continue; // 叶子节点跳过去
			int son = s[x].begin()->id; // 学会了
			s[fa[x]].erase({sz[x],x}); // 他的父节点删除这个点
			s[x].erase({sz[son],son});//他要删除他的长度最长那个子节点
			
			int t = sz[son];
			int t2 = sum[son];
			sz[son] = sz[x];
			sz[x] -= t;
			sum[son] = sum[x];
			sum[x] -= t2;
			
			fa[son] = fa[x];
			fa[x] = son;
			
			s[fa[son]].insert({sz[son],son});
			s[son].insert({sz[x],x});
		} 
	}
}

signed main()
{
  ios::sync_with_stdio(false);  cin.tie(0); cout.tie(0);
  int T; T = 1;
  while(T--) solve();
}

你可能感兴趣的:(图论,c++,算法,数据结构)