2023春训练2
vjudge链接:训练2
A.Make It Round
思维题,官方的题解很有道理?还是待理解
B.The Humanoid
思维题,思路来自官方题解
怎么说呢,首先想打更多的astronaut,这个evil humanoid必须要先考虑把自己能打过的astronaut都先打了壮大自身,之后再考虑嗑药。嗑药这里有个有意思的事就是不一定说当前磕3倍药就比2倍药好,所以说我们得考虑所有的情况,之后取大即可(这里实现的过程再好好想想)。
换者言之,其实这题就是考虑磕3倍药的时机,是第一次磕还是第二次、第三次。用一个for来遍历3倍药的嗑药时机也可以。最后,也是取大。
下见代码:
//>>>Qiansui
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<deque>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x,y,sizeof(x))
//#define int long long
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
using namespace std;
const int maxm=2e5+5,inf=0x3f3f3f3f,mod=998244353;
ll n,h,a[maxm];
ll solve(ll num,ll heal,ll g,ll b){
if(num==n) return 0;
if(heal>a[num]){//直接干
return solve(num+1,heal+a[num]/2,g,b)+1;
}
//尝试嗑药
ll ans1=0,ans2=0;
if(g) ans1=max(0ll,solve(num,heal*2,g-1,b));//2倍药
if(b) ans2=max(0ll,solve(num,heal*3,g,b-1));//3倍药
return max(ans1,ans2);
}
signed main(){
// ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int _=1;
cin>>_;
while(_--){
cin>>n>>h;
for(int i=0;i<n;++i) cin>>a[i];
sort(a,a+n);
cout<<solve(0,h,2,1)<<endl;
}
return 0;
}
D.Restore the Permutation
思维题
题目给你一个长度n和两两取大后的b数组,让你复原数组
首先需要判断b数组的合理性——b数组不能有重复数字
其次就是想怎么构造逻辑上最小的原数组,就是将给的大的b数组都放在两个的后面一个,其余的数在可以的条件下,从大到小从后往前放。
详见代码:
//>>>Qiansui
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<deque>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x,y,sizeof(x))
//#define int long long
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
using namespace std;
const int maxm=2e5+5,inf=0x3f3f3f3f,mod=998244353;
void solve(){
int n,b[maxm];
set<int> unused;
cin>>n;
vector<int> f(n+5,0),ans(n+5,0);
for(int i=1;i<=n/2;++i){
cin>>b[i];
ans[2*i]=b[i];//提前放在两两后面
++f[b[i]];//统计数字个数
}
for(int i=1;i<=n;++i){
if(f[i]==0){//统计未使用
unused.insert(i);
}else if(f[i]>1){//去重
cout<<-1<<endl;
return ;
}
}
for(int i=n;i>=2;i-=2){//找到unused中小于b[i]的最大数,找不到over
auto it=unused.upper_bound(ans[i]);
if(it==unused.begin()){
cout<<-1<<endl;
return ;
}
--it;//upper找到的是第一个大的,那么前一位就是小于等于的?
ans[i-1]=*it;
unused.erase(it);
}
for(int i=1;i<n;++i){
cout<<ans[i]<<' ';
}
cout<<ans[n]<<endl;
return ;
}
signed main(){
// ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int _=1;
cin>>_;
while(_--){
solve();
}
return 0;
}
E.Two Permutations
emmm,思维题,我自己的想法想复杂了,其实这题很简单
我的赘余代码——qiansui_code
很复杂对吧!
其实判断的部分如下就足以...(原谅赛时的我的蠢)
if((a==n&&b==n)||(a+b<n-1)){
cout<<"Yes\n";
}else{
cout<<"No\n";
}
F.Elimination of a Ring
思维题?好像cf好多看思维的。。。难到我了呜呜呜
这题呢,有个潜在的规则。如果说没发现的话,应该不太好整吧。
我们首先回顾题目的定义,成环的数据列首尾和相邻的数字均不相同。
我们考虑整个数据列(长度为n,n=1无需考虑。这里仅看n>2时)所包含的数字种类cnt。
①当cnt=2时,我们可以发现,n一定为偶数,而且两个数字相邻出现。所以这里我们在进行操作时,必定是消一自动消一,最后剩两个单独消。故最后的结果为1+\(\frac{n}{2}\)。
②当cnt>=3时,如果有相同的数存在,那么这两个数一定可以消一个。以此类推,最终一定可以全部消完。故最后的结果为\(n\)。
//>>>Qiansui
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<deque>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x,y,sizeof(x))
//#define int long long
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
using namespace std;
const int maxm=2e5+5,inf=0x3f3f3f3f,mod=998244353;
set<int> a;
void solve(){
a.clear();
int n,t,cnt=0;
cin>>n;
for(int i=0;i<n;++i){
cin>>t;
a.insert(t);
}
if(a.size()<=2) cout<<n/2+1<<endl;
else cout<<n<<endl;
return ;
}
signed main(){
// ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int _=1;
cin>>_;
while(_--){
solve();
}
return 0;
}