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);
}
}