深入解析:cf--思维训练

B. MIN = GCD

题目来源
难度:1100

解题思路

我们可以想到,这个最小值一定只能是整个数组中的最小值,因为如果不是,那么左半部分的最小值是大于它的,如果它在右半部分,那么整体的GCD是一定不等于左半部分的最小值的。
所以可以对数组进行升序排序,而且右半部分的数必须是能整除这个最小值的,这样才有可能整体GCD等于它。因此,排序后从2开始遍历,如过能整除最小值,就GCD一下,默认放在了右边,其余不能整除最小值的不用管,默认放在了左边,没有任何影响。这样一来,最后再比较判断最终的GCD值是否等于a[1](即最小值)

AC代码

#include<bits/stdc++.h>
  using namespace std;
  #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
  #define int long long
  #define PII pair<
  int,int>
  #define fi first
  #define se second
  #define endl '\n'
  const int N=1e5+6;
  int n,a[N];
  void solve()
  {
  cin>>n;
  for(int i=1;i<=n;i++)
  cin>>a[i];
  sort(a+1,a+1+n);
  int ans=0;
  for(int i=2;i<=n;i++)
  {
  if(a[i]%a[1]==0)
  ans=__gcd(ans,a[i]);
  }
  if(ans==a[1])cout<<
  "YES"<<endl;
  else cout<<
  "NO"<<endl;
  }
  signed main()
  {
  IOS;
  int _=1;
  cin>>_;
  while(_--)
  solve();
  return 0;
  }

C. Good Prefixes

题目来源
难度:1000

解题思路

什么是"好数组"?

  • 一个数组是"好数组",当且仅当里面存在一个元素,它等于数组中其他所有元素的总和。
    数组 [3, 1, 2] 是好数组,因为 3 = 1+2(第一个元素等于其他元素之和)
    数组 [2, 2, 3] 不是好数组,因为没有元素等于其他元素之和

需要计算这样的"好数组"前缀有多少个。

不难想到,要想是好数组,只能一个前缀中的最大值等于这个前缀中的其他值,那么我们可以用一个数组mx存储前i个数中的最大值,再用一个数组存前缀和,只要我们依次遍历,如果第i个位置的前缀和数组减去最大值还等于这个最大值的话,那他就是一个好数组。

AC代码

#include<bits/stdc++.h>
  using namespace std;
  #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
  #define int long long
  #define PII pair<
  int,int>
  #define fi first
  #define se second
  #define endl '\n'
  const int N=1e6+6;
  int n,a[N],s[N],mx[N];
  void solve()
  {
  cin>>n;
  int ans=0;
  fill(s,s+1+n,0);
  fill(mx,mx+1+n,0);
  for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)
    {
    mx[i]=max(mx[i-1],a[i]);
    //前i个元素中的最大值 
    s[i]=s[i-1]+a[i];
    //前缀和 
    }
    for(int i=1;i<=n;i++)
    if(s[i]-mx[i]==mx[i])ans++;
    cout<<ans<<endl;
    }
    signed main()
    {
    IOS;
    int _=1;
    cin>>_;
    while(_--)
    solve();
    return 0;
    }

B. Erase First or Second Letter

题目来源
难度:1100

解题思路

这道题很巧妙,操作一共就两种,删第一个和删第二个,如果删两次第一个和先删第一个再删第二个、先删第二个再删第一个都是完全相同的道理。这时候通过列举每种情况我们可以发现,只要判断第一个和第二个是否相同,然后利用动态规划的思想,其实就是前面已删除元素的去重之后的个数相加,就是最后能得出来的不同字符串个数。

AC代码

#include<bits/stdc++.h>
  using namespace std;
  #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
  #define int long long
  #define PII pair<
  int,int>
  #define fi first
  #define se second
  #define endl '\n'
  const int N=1e5+6;
  int n;
  char s[N];
  void solve()
  {
  cin>>n;
  int ans=0;
  for(int i=1;i<=n;i++)cin>>s[i];
    unordered_set<
    char>st;
    for(int i=1;i<=n;i++)
    {
    st.insert(s[i]);
    ans+=st.size();
    }
    cout<<ans<<endl;
    st.clear();
    }
    signed main()
    {
    IOS;
    int _=1;
    cin>>_;
    while(_--)
    solve();
    return 0;
    }

B. Digits

题目来源
难度:1100

解题思路

通过打表找规律即可,自己实践一下。

AC代码

#include<bits/stdc++.h>
  using namespace std;
  #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
  #define int long long
  #define PII pair<
  int,int>
  #define fi first
  #define se second
  #define endl '\n'
  const int N=1e6+6;
  int n,d;
  void solve()
  {
  cin>>n>>d;
  cout<<
  1<<
  " ";
  if(n>=3||d%3==0)cout<<
  "3 ";
  if(d==5)cout<<
  "5 ";
  if(n>=3||d==7)cout<<
  "7 ";
  if(n>=6||d==9||(n>=3&&d%3==0))cout<<
  "9";
  cout<<endl;
  }
  signed main()
  {
  IOS;
  int _=1;
  cin>>_;
  while(_--)
  solve();
  return 0;
  }

C. Robin Hood in Town

题目来源
难度:1100

解题思路

哇塞终于做一道二分答案的题了。
二分答案不熟悉的小伙伴欢迎看我这篇博客:二分查找&二分答案【模板+例题】带你精通二分!
其实很简单,就是照着题意去模拟。首先让找最小值,用尽量向左找的模板,其次这里需要f标记一下,只要能找到就标记为1,后续输出时如果f值为0说明一个也找不到就输出-1.
主要就是check函数怎么去写了,这里我们可以将数组a复制给辅助数组b,防止这次模拟后的结果影响下一个结果,然后按题目要求进行操作,求出有多少人财富严格少于平均财富的一半,用ans记录。最后返回ans>n/2即可。

AC代码

#include<bits/stdc++.h>
  using namespace std;
  #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
  #define int long long
  #define PII pair<
  int,int>
  #define fi first
  #define se second
  #define endl '\n'
  const int N=1e6+6;
  int n,a[N],b[N];
  int check(int mid)
  {
  double sum=0;
  for(int i=1;i<=n;i++)b[i]=a[i],sum+=b[i];
  sort(b+1,b+1+n);
  sum+=mid;
  b[n]+=mid;
  double x=1.0*sum/n/2;
  int ans=0;
  for(int i=1;i<=n;i++)
  if(b[i]<x)ans++;
  return ans>
  1.0*n/2;
  }
  void solve()
  {
  int f=0;
  cin>>n;
  for(int i=1;i<=n;i++)cin>>a[i];
    int l=0,r=1e18;
    while(l<r)
    {
    int mid=(l+r)/2;
    if(check(mid))r=mid,f=1;
    else l=mid+1;
    }
    if(f)cout<<r<<endl;
    else cout<<
    "-1"<<endl;
    }
    signed main()
    {
    IOS;
    int _=1;
    cin>>_;
    while(_--)
    solve();
    return 0;
    }
posted @ 2025-08-17 22:56  yfceshi  阅读(7)  评论(0)    收藏  举报