2022.3.22
CFAB训练赛5
A - Assigning to Classes
从小到大排序,找到中位数以及和它的下一位,最小值就是他们之差。因为总是可以分成两组,那么我们只需要让这两个数分别是不同组的中位数就可以了,至于这两组怎么排序并不重要。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=2e5+10,INF=1e8;
int a[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while(t--)
{
int n;
cin >> n;
for (int i = 1; i <=2* n;i++)
{
cin >> a[i];
}
sort(a+1,a+1+n*2);
int mid = (n*2 + 1) / 2;
int ans = abs(a[mid] - a[mid + 1]);
cout << ans << '\n';
}
return 0;
}
B - Chess Tournament
有2种期望,第一种是赢或者打平都行,但是别输。第二种是至少要赢一把,输或打平无所谓。对于第一种我们尽量让他们自己打平就好,对于第二种需要考虑情况是否存在,如果第二种只有一个人的话,因为他至少得赢一把,但是第一种的人都不能输,所以这时不存在。当第二种只有两个人的时候只能满足其中一个人赢一把,另外一个人就没法处理了,但是当三个或以上的人数时我们可以让他们形成一个环,轮着赢下去。接着就是如何输出的问题,对于第一种,我们输出=号,因为此时他的对手输出的也得是等于号。对于第二种,我们只需要让他们赢一把,剩下的可以随意输出-号,那么就先得输出一个+号,然后剩下的就要输出-号了。这里注意不能把两次的操作放在一个循环里,因为第一种操作会影响到第二种操作。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=100+10,INF=1e8;
char ans[N][N],a[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while(t--)
{
memset(ans, 0, sizeof ans);
int n;
cin >> n;
int cnt1 = 0, cnt2 = 0;
for (int i = 1; i <= n;i++)
{
cin >> a[i];
if(a[i]=='1')
cnt1++;
else
cnt2++;
ans[i][i] = 'X';
}
if(cnt2==1||cnt2==2)
cout << "NO" << '\n';
else
{
cout << "YES" << '\n';
for (int i = 1; i <= n;i++)
{
if(a[i]=='1')
{
for (int j = 1; j <= n;j++)
{
if(i==j)
continue;
ans[j][i] = ans[i][j] = '=';
}
}
}
for (int i = 1; i <= n;i++)
{
int f = 0;
for (int j = 1; j <= n; j++)
{
if(i==j)
continue;
if(ans[i][j]=='+'&&!f)
f = 1;
else if(!ans[i][j]&&!f)
{
ans[i][j] = '+';
ans[j][i] = '-';
f = 1;
}
else if(!ans[i][j]&&f)
{
ans[i][j] = '-';
ans[j][i] = '+';
}
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
cout << ans[i][j];
cout << '\n';
}
}
}
return 0;
}
C - Omkar and Heavenly Tree
一开始想歪了,想搞个双端队列判断该放前面还是放后面,越想越乱。后面观察b是不能出现在a和c之间的。但是如果有一个点没有出现在b这个位置,那么可以利用这个点与其他点独立成一条边,就像一个发散的球,这样可以保证b不会在a和c之间。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e8;
int vis[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while(t--)
{
memset(vis, 0, sizeof vis);
int n,m;
cin>>n>>m;
for (int i = 1;i<=m;i++)
{
int a,b,c;
cin>>a>>b>>c;
vis[b] = 1;
}
int x;
for (int i = 1;i<=n;i++)
if(!vis[i])
{
x = i;
break;
}
for (int i = 1;i<=n;i++)
{
if(i!=x)
{
cout << i << ' ' << x << '\n';
}
}
}
return 0;
}
D - Frog Jumps
因为如果在R这个格子的话只能往右跳,那么可以知道一定是从起点跳到第一个R,由最后一个R跳到终点,因为这两种情况都得满足,所以得去他们的最大值,然后在判断他们之间,相邻R的距离,最后取最大值。同时要注意没有R的情况。
当然可以在0和n+1处设置边界,把他们都标记成R,这样就可以不用考虑没有R的情况。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=2e5+10,INF=1e8;
char a[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while(t--)
{
cin >> a+1;
int n = strlen(a + 1);
//cout << n << '\n';
int ans, ans1, ans2;
int f = 0;
for (int i = 1; i <= n;i++)
{
if(a[i]=='R')
{
f = 1;
ans1 = i;
break;
}
}
for (int i = n; i >= 1;i--)
{
if(a[i]=='R')
{
f = 1;
ans2 = n+1-i;
break;
}
}
ans = max(ans1, ans2);
if(!f)
{
cout << n + 1 << '\n';
continue;
}
int x;
for (int i = 1; i <= n;i++)
{
if(a[i]=='R')
{
ans = max(ans, i - x);
x = i;
}
}
cout << ans << '\n';
}
return 0;
}
E - K-th Beautiful String
经过观察发现,每次bb连在一起的时候是有规律的,第一次经过1次最小字典序排列连在一起,第2次再经过2次连在一起,以此类推,我们根据循环不断减i的到k是属于第几次的,他的余数就是对于第几次的后面几次操作。再经过观察,后面几次操作就是以最开始的分开的那个字符串,然后b和b不断靠近。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=50+10,INF=1e8;
char a[N],ans[N][N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while(t--)
{
int i,n,k;
cin >> n>>k;
int cnt = 0;
for (int i = 1;;i++)
{
if(k>i)
{
k -= i;
}
else
{
cnt = i - 1;
break;
}
}
for (int i = 1; i <= n;i++)
{
if(i==n-cnt-1||i==n-k+1)
cout << "b";
else
cout << "a";
}
cout << '\n';
}
return 0;
}
F - Food Buying
可以发现,当每次花的钱少于10块是没有意义的,因为向下取整为0,这并不划算,于是我们不断花掉当前能花掉的最多的钱,也就是n-(n%10),然后再加上返还的钱,直到花到没钱为止。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=50+10,INF=1e8;
char a[N],ans[N][N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while(t--)
{
int n;
cin >> n;
int sum = 0;
while(n)
{
if(n>=10)
{
sum += n - (n % 10);
n = (n - (n % 10)/10+ (n % 10);
}
else
{
sum += n;
break;
}
}
cout << sum << '\n';
}
return 0;
}
G - Hide and Seek
因为这个东西可以被放在当前的格子的相邻的格子里,加入当前的格子第一次被询问的话,如果它相邻的格子最后一次被询问的时刻在当前这个格子之前的话我们可以在询问这个格子之前把东西放到已经被询问过了的相邻的格子里这样可以构成方案。于是我们需要记录每个数是否被询问,以及被询问的最早的时刻l[],和最后的时刻r[],对于当前的数i,如果i>=2或i<=n-1并且它相邻的格子最晚出现的时刻在它之前的话就可以构成方案。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e8;
int a[N], l[N], r[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n, m, ans = 0;
cin >> n >> m;
for (int i = 1; i <= m; i++)
cin >> a[i];
for (int i = 1; i <= n;i++)
{
l[i] = INF, r[i] = -INF;
}
for (int i = 1; i <= m;i++)
{
l[a[i]] = min(l[a[i]], i);
r[a[i]] = max(r[a[i]], i);
}
for (int i = 1; i <= n;i++)
{
if(l[i]>r[i])
ans++;
if(i>=2&&r[i-1]<l[i])
ans++;
if(i<=n-1&&r[i+1]<l[i])
ans++;
}
cout << ans << '\n';
return 0;
}
H - Two Regular Polygons
如果某个正多边形能够包含另一个正多边形这个大的多边形的边数一定可以整除小多边形的边数。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=50+10,INF=1e8;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while(t--)
{
int n, m;
cin >> n>>m;
if(n%m!=0)
{
cout << "NO" << '\n';
}
else
cout << "YES" << '\n';
}
return 0;
}
I - Construct the String
在长度a固定的连续区间里必须有b个不同的字母,从a开始枚举到长度a,然后不断循环。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e8;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while(t--)
{
int n, a, b;
cin >> n >> a >> b;
int cnt = 0;
for (int i = 1; i <= n;i++)
{
char x;
if(cnt==b)
cnt = 0;
x = 'a' + cnt;
cnt++;
cout << x;
}
cout << '\n';
}
return 0;
}
J - Gregor and the Pawn Game
如果当前的格子对面的格子没有兵的话直接走过去就可以了,答案+1,如果有兵的话做两次循环,一次向左走,一次向右走,同时需要更新哪些格子已经被占了,不能再选。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e8;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while(t--)
{
int n,cnt=0;
cin>>n;
string a, b;
cin >> a;
cin >> b;
for (int i = 0; i < n;i++)
{
if(b[i]=='1')
{
if(a[i]=='0')
cnt++;
else if(i!=0&&a[i-1]=='1')
cnt++, a[i - 1] = '0';
else if(i!=n&&a[i+1]=='1')
cnt++, a[i + 1] = '0';
}
}
cout << cnt << '\n';
}
return 0;
}
K - Productive Meeting
开会,如果0的人就不用选了,直接走,对于其他人我们把他们能聊的次数和编号加入优先队列,每次取出前2个大的让他们聊,可以避免后面的人没得聊的情况。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=2e5+10,INF=1e8;
pii ans[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while(t--)
{
priority_queue<pii> que;
int n;
cin >> n;
for (int i = 1; i <= n;i++)
{
int x;
cin >> x;
if(x>0)
{
que.push({x, i});
}
}
int cnt = 0;
while(que.size()>=2)
{
auto t = que.top();
que.pop();
auto tt = que.top();
que.pop();
ans[++cnt] = {t.second, tt.second};
if(t.first>1)
que.push({t.first - 1, t.second});
if(tt.first>1)
que.push({tt.first - 1, tt.second});
}
cout << cnt << '\n';
for (int i = 1; i <= cnt;i++)
cout << ans[i].first << ' ' << ans[i].second<<'\n';
}
return 0;
}
L - Ticks
对于每个星点,遍历它的坐上角和右上角,看是否符合条件长度大于k,如果符合就标记一下。最后再完整遍历整张图,如果有点是星号但是没有被标记过说明这是不符合的。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=20+10,INF=1e8;
char a[N][N];
int vis[N][N];
int main()
{
int t;
cin >> t;
while(t--)
{
memset(vis, 0, sizeof vis);
int n, m, k;
cin >> n >> m >> k;
for(int i=1;i<=n;i++)
cin >> a[i]+1;
int cnt=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i][j]=='*')
{
int ans=1;
while(a[i-ans][j-ans]=='*'&&a[i-ans][j+ans]=='*')
{
ans++;
}
ans--;
if(ans>=k)
{
for(int k=0;k<=ans;k++)
{
vis[i-k][j-k]=1;
vis[i-k][j+k]=1;
}
}
}
}
}
int f=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(!vis[i][j]&&a[i][j]=='*')
{
f=0;
break;
}
}
if(!f)
break;
}
if(f)
cout << "YES" << '\n';
else cout << "NO" << '\n';
}
return 0;
}