今天做了一遍 蓝桥杯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一道!