<蓝桥杯备考刷题>蓝桥杯15届省赛冲刺营结营考试:七彩之城的独特序列+完美队列的数目(关于子序列的理解)

今天做了一遍 蓝桥杯15届省赛冲刺营结营考试 遇到的问题还不小

对于子序列的问题不透彻(只知道dp中最长递增子序列)

其实做完这些题后 我明白了子序列和子数组的差别和相同的点

那么遇到子序列问题 一般不会让你排序 因为最后要求的答案一般都是有序的

包括子数组问题 所以我想告诉大家我对于这类题目的理解:

第六题:

七彩之城的独特序列

对于这样的一个题目 我的第一想法就是排列组合 最后我发现排列组合会打乱原本因该有的次序,并且排列组合的时间复杂度是非常高的:大概是O(n!)这么大所以我没有想着怎么去写了 并且第一次写的时候我居然以子数组的形式去写!大家记得审题子数组和子序列问题!!!!


第一次代码:

#include <bits/stdc++.h>
using namespace std;
int n;
const int N = 1e5+10;
int arr[N];
int ans=  0;
int main()
{
  cin>>n;
  for(int i =1;i<=n;i++){
    cin>>arr[i];
  }
  for(int len = 1;len<=n;len++){
    for(int i = 1;i+len-1<=n;i++){
      int j = i+len-1;
      unordered_set<int> s;
      for(int k = i;k<=j;k++){
        s.insert(arr[i]);
      }
      if(s.size()==len) ans++;
    }
  }
  cout<<ans;
  // 请在此输入您的代码
  return 0;
}

很明显时间复杂度为O(n^3)直接爆了 但是我就只想骗骗分0.0

后面发现完全错误直接归为0分 就是用了子数组的思想


然后最后我认识到了子序列的问题 -》它实际上是一个开关的问题

什么是开关呢?

假设这是我们的数组,如果要取一个没有相同元素的子序列 那么每个元素我们都可以选可以不选并且位置不会发生改变(该在你前面的总会在你前面)这就符合我们的开关

这就是开关的问题!那么我们的1元素可以选可以不选 2元素可以选第一个 可以选第二个 可以选第三个 可以不选 这四种情况 那么每个元素的情况实际上就是存在的元素的个数+1

那么最后的答案即是:所有元素的可选择数量相乘(特判:不能一个都不选)


#include <bits/stdc++.h>
using namespace std;
int n;
const int N = 1e5+10,MOD = 1e9+7;
long long arr[N];
long long ans=  1;
int main()
{
  cin>>n;
  
  unordered_map<int,int> mp;
  for(int i =1;i<=n;i++){
    cin>>arr[i];
    mp[arr[i]]++;
  }
  for(auto s:mp){
    ans*=s.second+1;
    ans%=MOD;
  }
  cout<<(ans-1)%MOD;
  // 请在此输入您的代码
  return 0;
}

这就是我们的正解

那么来看第二个题目:完美队列的数目

这个题目是整套卷子的第八题(都是关于子序列问题0.0)

这个题目针对于选法 那么我们可以先把所有元素排序 并且每次都给定一个区间,去判断区间这个区间是否合法(合法是指最弱的和最强的和<=k)

那么其实这个问题也是一个开关问题 

我们看这个题目的开关实际上是每个区间中的开关 那么每个人可以选可以不选 则每个人有2种选法,最终一个合法区间的答案就是 2^(l-r)

我们直接上代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10,MOD = 1e9+7;
typedef long long LL;
LL arr[N];
int n, k;
LL ans;
LL qmi(int a,int b,int c){
  LL ans= 1;
  while(b){
    if(b&1) ans = (LL) ans*a%c;
    b>>=1;
    a = (LL) a*a%c;
  }
  return ans;
}
int main()
{
    // 请在此输入您的代码
    cin >> n >> k;
    for (int i = 1; i <= n; i++){
      cin >> arr[i];
      if(arr[i]*2<=k) ans++;
    }
    sort(arr + 1, arr + n + 1);
    int l = 1,r = n;
    while(l<=r){
      if(arr[l]+arr[r]>k){
        r--;
      }else{
        ans = (ans+qmi(2,r-l,MOD)-1)%MOD;
        l++;
      }
    }
    cout << ans;
    return 0;
}

因为常规的pow函数时间复杂度为N 那么总时间复杂度为N^2一定会超时 这里可以用到快速幂(qmi)模板来解决

并且区间不需要全部去枚举 只需要用一个滑动窗口的方法(双指针)可以使得复杂度为N

总体时间复杂度为NlogN 完美解决数据为1e5的问题

最后:

又ac一道!


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值