题意:两个人在一个n*m的01矩阵上玩游戏,一个人每轮选择一个位置(y,x)将其置为一,要求是y行无1,x列无1。当一个人无法选择符合条件的点时,他失败。
思路:统计有多少个空行以及空列,符合条件的点的数目为其中的小值,当这个值为奇数时先手胜,否则后手胜。
代码:
#include <iostream>
using namespace std;
const int N = 55;
int a[N][N], r[N], c[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T, n, m;
cin>>T;
while(T--){
cin>>n>>m;
for(int i = 0; i < n; ++i) r[i] = 0;
for(int i = 0; i < m; ++i) c[i] = 0;
for(int i = 0; i < n; ++i){
for(int j = 0; j < m; ++j){
cin>>a[i][j];
if(a[i][j]){
r[i] = 1; c[j] = 1;
}
}
}
int a = n, b = m;
for(int i = 0; i < n; ++i)
if(r[i]) a -= 1;
for(int i = 0; i < m; ++i)
if(c[i]) b -= 1;
a = min(a, b);
if(a%2==1){
cout<<"Ashish\n";
}else{
cout<<"Vivek\n";
}
}
return 0;
}
题意:给你一个长度为n的数组,数组的元素除了值以外还有种类为{0,1},你可以进行以下操作:选择种类不同的两个元素然后交换他们的位置。问是否通过该操作得到一个非递减序列。
思路:如果数组中包含了两个种类的元素,那么我们可以任意安排元素位置,即满足要求。如果只包含一种元素,那么判断一下原数组是否非递减即可。
代码:
#include <iostream>
using namespace std;
const int N = 5e2+10;
int a[N], b[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T, n;
cin>>T;
while(T--){
cin>>n;
int sum = 0;
for(int i = 0; i < n; ++i){
cin>>a[i];
}
for(int i = 0; i < n; ++i){
cin>>b[i];
sum += b[i];
}
if(sum != 0 && sum != n){
cout<<"Yes\n"; continue;
}
int flag = 0;
for(int i = 1; i < n; ++i){
if(a[i] < a[i-1]){
flag = 1; break;
}
}
if(flag){
cout<<"No\n";
}else{
cout<<"Yes\n";
}
}
return 0;
}
题意:给你两个长度为n的permutation,我们定义好对为两个permutation上同一位置且值相等的对。现在我们可以对permutation中元素进行如下操作:将所有元素位置左移或者右移x个位置,比如我们左移1个位置,那么x0 = x1, x1 = x2,''''''xn-1 = x0。问我们通过该操作能得到的最多好对是多少。(其中的长度为n的permutation即为元素1~n在permutation中出现各为一次的排列;
思路:由于是整体移动,那么a与b之间的相等元素形成了一个映射,具有同样位置差的映射的数量即为答案。
代码:
#include <iostream>
using namespace std;
const int N = 2e5+10;
int a[N], pos[N], num[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int n;
cin>>n;
for(int i = 0; i < n; ++i){
cin>>a[i];
}
int t;
for(int i = 0; i < n; ++i){
cin>>t;
pos[t] = i;
}
for(int i = 0; i < n; ++i){
++num[(i-pos[a[i]]+n)%n];
}
int ans = 0;
for(int i = 0; i < n; ++i){
ans = max(ans, num[i]);
}
cout<<ans<<'\n';
return 0;
}
题意:在一个n*m的迷宫中,有四种元素:'.', 'G', 'B', '#'。其中的'.'表示空地,'G'表示好人,'B'表示坏人,'#'表示墙。出口位置为(n,m),其中墙不可通过,人的移动方式是东南西北,你可以将空地置为墙,出口保证初始是空地。问是否有一种放置方法使得所有好人都能到达出口,没有坏人能到达出口。
思路:要想坏人不能达到出口,那么必须要有墙使得没有路径可以通向出口,其中,最好的放置方式就是将他的东南西北位置都置为墙,因为如果是其它方式,那么影响的面积肯定比这种方式要大,更有可能导致好人无法到达出口。因此,我们将每一个坏人的东南西北位置按规则置为墙,最后对出口做一次dfs,即可得到答案。
代码:
#include <iostream>
#include <cstring>
using namespace std;
const int N = 55;
int n, m;
int vis[N][N];
char a[N][N];
void dfs(int y, int x)
{
if(y <= 0 || y > n || x <= 0 || x > m || vis[y][x] || a[y][x] == '#')
return ;
vis[y][x] = 1;
dfs(y-1,x); dfs(y+1,x); dfs(y,x+1); dfs(y,x-1);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T;
cin>>T;
while(T--){
cin>>n>>m;
memset(vis, 0, sizeof vis);
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= m; ++j){
cin>>a[i][j];
}
}
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= m; ++j){
if(a[i][j] == 'B'){
if(a[i][j-1] == '.') a[i][j-1] = '#';
if(a[i][j+1] == '.') a[i][j+1] = '#';
if(a[i-1][j] == '.') a[i-1][j] = '#';
if(a[i+1][j] == '.') a[i+1][j] = '#';
}
}
}
int flag = 0;
dfs(n, m);
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= m; ++j){
if((a[i][j]=='G'&&vis[i][j]==0)||(a[i][j]=='B'&&vis[i][j]==1)){
flag = 1;
}
}
}
if(flag){
cout<<"No\n";
}else{
cout<<"Yes\n";
}
}
return 0;
}
题意:给你一个数组,你可以选择k个元素,你得到的值为这k个元素的或,即(a1|a2|...|ak)。但如果这个结果中的二进制下的某一位1在k个元素中出现的次数小于(k-2)次时,该位置为0。问可以得到的最大值是多少。
思路:由于是(k-2)次,那么我们考虑先选择3个元素,此时结果即为3个元素的或,现在如果我们想给结果某一位变为1,那么我们就得选择一个该位为1的数,但同时我们也需要已经选择的三个元素中至少有一个元素在该位上也为1,但这样只会使结果更坏,因此,结果就是选择三个数,由数据范围直接枚举即可。
代码:
#include <iostream>
using namespace std;
typedef long long ll;
const int N = 5e2+10;
ll a[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int n;
ll ans = 0;
cin>>n;
for(int i = 0; i < n; ++i){
cin>>a[i];
}
if(n == 1){
ans = a[0];
}else if(n == 2){
ans = a[0]|a[1];
}
for(int i = 0; i < n; ++i){
for(int j = i+1; j < n; ++j){
for(int k = j+1; k < n; ++k){
ans = max(ans, a[i]|a[j]|a[k]);
}
}
}
cout<<ans<<'\n';
return 0;
}