卡车上的最大单元数
思路:贪心
按照能装载的单元数量从大到小排直接选即可
class Solution {
public:
int maximumUnits(vector<vector<int>>& b, int t) {
sort(b.begin(),b.end(),[](vector<int> a,vector<int> b){
return a[1]>b[1];
});
int ans=0;
for(auto &x:b){
if(t>=x[0]){
t-=x[0];
ans+=x[0]*x[1];
}
else {
ans+=x[1]*t;
break;
}
}
return ans;
}
};
大餐计数
思路:哈希
开个map记录前面的数字,注意到范围,所以暴力枚举1、2、4…2^21
一边计算一边取模即可
const int mod=1e9+7;
typedef long long ll;
class Solution {
public:
int mp[1<<22];
int countPairs(vector<int>& d) {
ll ans=0;
for(auto &x:d){
for(int i=0;i<=21;i++){
if((1<<i)>=x)ans+=mp[(1<<i)-x];
if(ans>=mod) ans-=mod;
}
mp[x]++;
}
return ans;
}
};
将数组分成三个子数组的方案数
思路:将序列分成了三部分,那么就是有两个分界线,将序列分成了三部分,所以我们枚举第一个区间left的右边界,然后二分出来二倍left的区间和,计算出来第二个区间的右端点的最小位置pos1。然后我们去计算第二个区间右端点的最远位置pos2就好了,贡献就是pos2-pos1+1
注意:区间要求非空,所以
pos1=max(pos1,i+1)
pos2=min(pos2,n-1)
当时因为这个wa了两发。。
可以先前缀和求一下 方便求区间的和
typedef long long ll;
const ll mod=1e9+7;
class Solution {
public:
ll s[1<<20];
int waysToSplit(vector<int>& nums) {
int n=nums.size();
for(int i=1;i<=n;i++){
s[i]=s[i-1]+nums[i-1];//前缀和
}
ll ans=0;
for(int i=1;i<=n;i++){
int pos1=lower_bound(s+1,s+n+1,2*s[i])-s;
pos1=max(pos1,i+1);//第二个区间的满足要求的第一个右端点pos1
if(pos1<n){
ll sum=s[n]-s[i];
int pos2=upper_bound(s+1,s+n+1,s[i]+sum/2)-s;
pos2--;//使得第二个区间小于等于第三个区间和
pos2=min(pos2,n-1);//注意第三个区间非空 所以右端点最多到n-1
if(pos2>=pos1){
ans+=pos2-pos1+1;
ans%=mod;
}
}
}
return ans;
}
};
得到子序列的最少操作次数
思路:很容易知道直接求最长公共子序列即可,但是数据范围不允许n^2的时间复杂度
所以考虑别的做法。容易发现arr数组中在target中不存在的元素是没用的。
注意到target中的元素互不相同。
所以我们对target按顺序进行1 2 3 …n进行编号
然后对在arr数组中在target的元素求一下最长上升子序列就好了。
map<int,int>mp;
class Solution {
public:
int minOperations(vector<int>& t, vector<int>& a) {
mp.clear();
for(int i=0;i<t.size();i++){
mp[t[i]]=i+1;
}
vector<int> b;
for(auto &x:a){
if(!mp[x]) continue;
if(b.size()){
if(mp[x]>b[b.size()-1]) b.push_back(mp[x]);
else{
int pos=lower_bound(b.begin(),b.end(),mp[x])-b.begin();
b[pos]=mp[x];
}
}
else b.push_back(mp[x]);
}
return t.size()-b.size();
}
};