A:Find Array
题意:
构造一个长度为 \(n\) 序列 \(a\) ,使得任意 \(a_i\) 不被 \(a_{i-1}\) 整除
思路:
签到题,\(2\) 到 \(n+1\) 顺序输出即可
B:Build the Permutation
题意:
给定峰的个数 \(a\) 和谷的个数 \(b\) ,构造一个长度为 \(n\) 的序列使得它恰好有 \(a\) 个峰 \(b\) 个谷,并判断是否有解
思路:
简单分讨题,先判断无解
- 当峰的个数或谷的个数大于 \((n-1)/2\) 时,显然无解
- 当峰和谷数量之差大于 \(1\) 时,必然无解,因为想再产生一个峰或谷需要一个谷或峰
然后大力分讨 \(a=b\) 和 \(\lvert a-b \rvert=1\) 即可
这里给出一种构造方法:
- 当 \(a=b+1\) 时,前面先把 \(a\) 搞全,后面一直降
- 当 \(a+1=b\) 时,前面把 \(b\) 搞全,然后一直升
- 当 \(a=b\) 时,前面把 \(a\) 搞全,然后一直升,当然也可以理解成把 \(b\) 搞全,然后一直降
代码:
#include<bits/stdc++.h>
using namespace std;
int n,t,a,b;
int main()
{
cin>>t;
while(t--)
{
cin>>n>>a>>b;
if((n-1)/2<a||(n-1)/2<b||abs(a-b)>1)
{
cout<<"-1\n";
continue;
}
if(a==b)
{
int m=n-a*2;
int now=1;
a++;
if(a*2>n)
{
cout<<"-1\n";
continue;
}
int k=a;
while(k--)
{
cout<<now<<" "<<now+a<<" ";
now++;
}
now+=a;
for(int i=now;i<=n;i++) cout<<i<<" ";
}
else if(a+1==b)
{
int m=b*2;
int k=b;
for(int i=m;k>0;i--,k--) cout<<i<<" "<<i-b<<' ';
for(int i=m+1;i<=n;i++) cout<<i<<" ";
}
else if(a==b+1)
{
int m=n-a*2,k=a;
for(int i=1;k>0;i++,k--) cout<<m+i<<" "<<m+i+a<<" ";
for(int i=m;i>=1;i--) cout<<i<<" ";
}
puts("");
}
}
C: Game Master
题意:
给定 \(n\) 个人分别在两张地图上的能力值,每次选出其中两人在任意地图上战斗,能力值低者被淘汰,获胜者为最后没被淘汰的那个人,问那些人可以通过控制比赛获胜,那些人一定无法获胜
思路:
考虑那些必败者,要么打不过任何人,要么能打过的人打不过任何人,要么能打过的人能打过的人打不过任何人,以此类推,所以很容易搞出一个 \(O(n^n)\) 的垃圾算法,考虑优化
不妨将两个能力值分别排序,并记录所属编号,从后往前扫,可以发现,如果存在一个位置 \(i\) ,使得分别在两个图中前 \(i\) 强的人都是某 \(i\) 个人,那么它内部一定每个人都能在这 \(i\) 个人的集合中获胜,并且不在这个集合中的任意一个人一定都打不过这个集合里的任意一个人,然后在这 \(i\) 个人的集合中的人一定都能获胜,剩下的必败
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
pair<int,int>a[(int)(1e5+10)],b[(int)(1e5+10)];
set<int>s;
char ans[(int)(1e5+10)];
signed main()
{
int t;cin>>t;
while(t--)
{
int n;cin>>n;
s.clear();
for(int i=0;i<=n-1;i++)
{
cin>>a[i].first;a[i].second=i;
}
for(int i=0;i<=n-1;i++)
{
cin>>b[i].first;b[i].second=i;
ans[i]='0';
}
sort(a,a+n);sort(b,b+n);
ans[n]=0;
int i;
for(i=n-1;i>=0;i--)
{
s.insert(a[i].second);
s.insert(b[i].second);
if(s.size()==n-i) break;
}
while(i<=n-1) ans[a[i].second]='1',i++;
puts(ans);
}
}