思路:
对于一个点(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;
}
思路:
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;
}
思路:
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();
}
#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();
}