首先
Cue一下隊友鏈接:
核心選手:https://me.csdn.net/qq_43559193
核心選手:https://me.csdn.net/weixin_43916298
比賽鏈接:https://codeforces.ml/contest/1362
目錄
A. Matrix Game
題目大意:
兩個人玩遊戲,每個人可以放石子,放石子的要求是當且僅當 該行或者該列沒有石子,不能放石子的人失敗。
給出初始棋盤佈局
雙方都採取最優策略,問誰會贏?
題目思路:
博弈論嘛。
再結合這個題是A題,肯定不是太難的博弈。
必輸態很容易,就是沒有行與列可以,所以看一下行與列的最小值
判斷一下奇偶性就可以了
Code:
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF=1e18;
const int maxn=1e6+6;
const int mod=1e9+7;
const double eps=1e-15;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll mp[105][105];
int main(){
int T;scanf("%d",&T);
while(T--){
read(n);read(m);
for(int i=1;i<=n;i++){
for(int k=1;k<=m;k++)
read(mp[i][k]);
}
ll ans = 0,ans1 = 0;
for(int i=1;i<=n;i++){
ll p = 0;
for(int k=1;k<=m;k++){
if(mp[i][k]) break;
if(k == m) ans++;
}
}
for(int k=1;k<=m;k++){
for(int i=1;i<=n;i++){
if(mp[i][k]) break;
if(i == n) ans1++;
}
}
ll temp = min(ans,ans1);
if(temp&1) printf("Ashish\n");
else printf("Vivek\n");
}
return 0;
}
/**
1[2[a]3[b]4[1[b]2[c]]]
aabbb[bccb
**/
B. Trouble Sort
題目大意:
給出一個a數組與b數組,ai與aj可以交換當且僅當bi!=bj
b數組只包含0、1
問能否通過若干次交換後使得a數組單調不下降
題目思路:
首先明白一個結論:01同時存在一定可以(老結論了,不信可以證明一下:所有交換的元素都可以通過一個元素進行交換,實現兩者的交換)
沒有01同時存在的話,只能看原數組是否有序了
Code:
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF=1e18;
const int maxn=1e6+6;
const int mod=1e9+7;
const double eps=1e-15;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll a[maxn],b[maxn];
struct node{
ll w;
int id;
}save[maxn];
int main(){
int T;scanf("%d",&T);
while(T--){
read(n);
int f = 0;
a[0] = -1;
for(int i=1;i<=n;i++){
read(a[i]);
if(a[i]<a[i-1]) f = 1;
}
ll f1 = 0,f2 = 0;
for(int i=1;i<=n;i++){
read(b[i]);
if(b[i]) f1++;
else f2++;
}
// debug(f1);
// debug(f2);
if(!f1||!f2){
if(f) printf("No\n");
else printf("Yes\n");
}
else printf("Yes\n");
}
return 0;
}
/**
1[2[a]3[b]4[1[b]2[c]]]
aabbb[bccb
**/
C. Rotation Matching
題目大意:
給出a,b兩個數組,每次使得a向左或者向右移動k位(k取任意值),問最大能有多少個ai = bi
題目思路:
首先,由於沒有規定移動位數的限制,所以向右移動可以代替向左移動
所以控制b不變,使得a向右移動,此時最多移動n-1位,超過n-1位就爲一個循環節了
所以看一下每個數字可以移動多少位才能與b中的數字對應
最後求移動位數貢獻的最大值,就是數字個數了
一個經驗:做過很多全排列的題、基本都跟位置有關係,因爲全排列 位置 -> 值 是一個一一映射
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF=1e18;
const int maxn=1e6+6;
const int mod=1e9+7;
const double eps=1e-15;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll a[maxn],b[maxn];
int pos[maxn];
int val[maxn];
int main(){
read(n);
for(int i=1;i<=n;i++) read(a[i]);
for(int i=1;i<=n;i++){
read(b[i]);
pos[b[i]] = i;
}
for(int i=1;i<=n;i++){
int temp = pos[a[i]];
if(temp>=i) val[temp-i]++;
else val[n-i+temp]++;
}
int maxl = 0;
for(int i=0;i<=n-1;i++){
maxl = max(maxl,val[i]);
}
printf("%d\n",maxl);
return 0;
}
/**
1[2[a]3[b]4[1[b]2[c]]]
aabbb[bccb
**/
D. Solve The Maze
題目大意:
給出一張地圖,G是好人,B是壞人,.是空地,#是牆,終點是n,m
問能否讓一些點變爲牆,從而使得所有的好人都能到達終點,而所有的壞人都到達不了終點。
題目思路:
考慮把壞人封鎖起來,然後看所有好人能否到達終點即可
如何封鎖是個問題、這裏也是莽了一下,首先貪心的去想,如果要對好人的影響最小,那麼封鎖的範圍應該最小。
所以首先考慮 B 能否到達終點,如若不到達終點不需要封鎖
到達終點的話,莽了一下,封鎖相鄰的四個點。
然而過了,有沒有大佬可以證明一下這是正確的,評論區可以討論(我感覺有一種方案,封鎖下出口,而不封鎖上出口,因爲上出口到達不了,然而此時封鎖上出口會使得有一個好人不過,就這種情況,不知道我想複雜了還是怎麼)
封鎖之後,再看一下所有好人是否都可以到就可以了
Code:
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF=1e18;
const int maxn=1e6+6;
const int mod=1e9+7;
const double eps=1e-15;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
char mp[105][105];
int visp[55][55];
int vis[55][55];
int dx[4] = {0,0,-1,1};
int dy[4] = {1,-1,0,0};
int judge(int x,int y){
if(x>=1&&x<=n&&y>=1&&y<=m&&mp[x][y]!='#') return 1;
return 0;
}
int bfs(int sx,int sy){
queue<pair<int,int>>q;
for(int i=1;i<=n;i++){
for(int k=1;k<=m;k++){
vis[i][k] = 0;
}
}
if(mp[sx][sy] == '#') return 0;
q.push({sx,sy});
vis[sx][sy] = 1;
while(!q.empty()){
auto u = q.front();q.pop();
int x = u.first,y = u.second;
for(int i=0;i<4;i++){
int mx = x+dx[i],my = y+dy[i];
if(judge(mx,my)&&!vis[mx][my]){
q.push({mx,my});
vis[mx][my] = 1;
}
}
}
return vis[n][m];
}
int main(){
int T;scanf("%d",&T);
while(T--){
read(n);read(m);
memset(visp,0,sizeof(visp));
for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
bfs(n,m);
for(int i=1;i<=n;i++){
for(int k=1;k<=m;k++){
if(mp[i][k] == 'B'&&vis[i][k]) visp[i][k] = 1;
}
}
int f = 0;
for(int i=1;i<=n;i++){
for(int k=1;k<=m;k++){
if(visp[i][k]){
for(int j=0;j<4;j++){
int mx = i +dx[j],my = k+dy[j];
if(judge(mx,my)){
if(mp[mx][my] == 'G') f = 1;
mp[mx][my] = '#';
}
}
}
}
}
bfs(n,m);
for(int i=1;i<=n;i++){
for(int k=1;k<=m;k++){
if(mp[i][k]=='G'&&!vis[i][k]) f = 1;
}
}
if(f) printf("No\n");
else printf("Yes\n");
}
return 0;
}
/**
3
011
100
111
**/
E. Maximum Subsequence Value
題目大意:
要求你選出一段子序列,假設長度爲k,將這個子序列的個元素二進制拆分。
如果第i位上的1的個數 >= max(k-2,1) 那麼該位就會貢獻 2^i
問子序列的最大貢獻是多少?
題目思路:
k只可以取1、2、3
這裏證明一下:
其實1 2 3顯然成立,所以只需要證明大於3的不會產生比1 2 3大的貢獻即可
如果一段序列 在第i位上不滿足,那麼如果擴充元素的個數,新增元素在該位只能是0或者1
如果是0,序列長度增加1,限制條件max(k-2,1)也增加1,但是該位沒有增加,所以不會產生貢獻
如果是1,序列長度增加1,限制條件max(k-2,1)也增加1,該位增加+1,因爲之前不滿足,所以現在也不滿足
所以,對於長度爲3的子序列來說,如果想要在其上面擴充元素,滿足的一定還滿足,不滿足的一定還是不滿足,所以擴充是沒有用的。
所以只需要考慮1、2、3的情況
Code:
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF=1e18;
const int maxn=1e6+6;
const int mod=1e9+7;
const double eps=1e-15;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll num[maxn];
ll c[65];
vector<int>v;
int main(){
read(n);
ll maxl = 0;
for(int i=1;i<=n;i++){
read(num[i]);
maxl = max(maxl,num[i]);
for(int k=0;k<=62;k++) c[k] += ((num[i]>>k&1)?1:0);
}
for(int i=1;i<=n;i++){
for(int k=i+1;k<=n;k++){
maxl = max(maxl,num[i]|num[k]);
}
}
for(int i=1;i<=n;i++){
for(int k=i+1;k<=n;k++){
for(int j=k+1;j<=n;j++){
maxl =max(maxl,((num[i]|num[k])|num[j]));
}
}
}
printf("%lld\n",maxl);
return 0;
}
/**
3
011
100
111
**/
F. Swaps Again
題目大意:
給出a數組和b數組,每次可以對a數組進行操作,將前k個與後k個交換(k<n/2)。
問若干次交換後能否得到數組b
題目思路:
這個應該是規律或者結論題?
首先要發現一個性質:如果x和y對稱,那麼無論怎麼交換依然對稱。
1 2 5 6 :1對應6 ,2對應5
交換後:
5 6 1 2:1依然對應6,2依然對應5
所以我們就只需要看一下b數組的對應關係,如果a數組可以滿足這所有的對應關係,那麼每組對應關係無論怎麼交換都是可以得到的
所以只需要考慮一下對稱性判斷就好了,怎麼判斷對稱性呢?
a_i太大了,但是n確很小,所以考慮把a_i離散化,用一個二維數組來標記一下
a[x][y]標記一下x對應y的關係有多少個
看a中的關係能否全部滿足即可:此時注意關係是雙向的,需要雙向判斷
Code:
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF=1e18;
const int maxn=1e6+6;
const int mod=1e9+7;
const double eps=1e-15;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll num[maxn];
ll judge[505][505];
vector<int>v;
int getid(ll x){
return lower_bound(v.begin(),v.end(),x)-v.begin() +1;
}
ll a[maxn],b[maxn],c[maxn],d[maxn];
int main(){
int T;scanf("%d",&T);
while(T--){
read(n);
for(int i=0;i<=n;i++){
for(int k=0;k<=n;k++){
judge[i][k] = 0;
}
}
v.clear();
for(int i=1;i<=n;i++){
read(a[i]);
c[i] = a[i];
v.push_back(a[i]);
}
for(int i=1;i<=n;i++){
read(b[i]);
d[i] = b[i];
}
sort(a+1,a+1+n);
sort(b+1,b+1+n);
int f = 0;
for(int i=1;i<=n;i++){
if(a[i] != b[i]) f = 1;
}
if(f){
printf("No\n");
continue;
}
sort(v.begin(),v.end());//排序
v.erase(unique(v.begin(),v.end()),v.end());
for(int i=1;i<=n;i++){
int id1 = getid(c[i]);
int id2 = getid(c[n-i+1]);
judge[id1][id2]++;
judge[id2][id1]++;
}
for(int i=1;i<=n;i++){
int id1 = getid(d[i]);
int id2 = getid(d[n-i+1]);
if(judge[id1][id2]>0&&judge[id2][id1]>0){
judge[id1][id2] --;
judge[id2][id1] --;
}
else{
f = 1;
break;
}
}
if(f) printf("No\n");
else printf("Yes\n");
}
return 0;
}
/**
3
011
100
111
**/