题目链接:蓝桥云课
1.寻找食物储量
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,x;
int a[1000010];
signed main()
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
cin>>x;
auto t=lower_bound(a,a+n,x)-a;
if(t==n)
{
cout<<-1<<endl;
}
else
{
cout<<t+1<<endl;
}
return 0;
}
题目意思告诉你是顺序排序,所以可以联想到二分查找(前提是顺序排序)
2.挑选子串
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,k,sum1=0;
int a[2010];
signed main()
{
cin>>n>>m>>k;
for(int i=1; i<=n; i++)
{
cin>>a[i];
}
for(int i=1; i<=n; i++)
{
int sum=0; //统计的应该是每个子串满足的个数
for(int j=i; j<=n; j++) //遍历所有可能的子串 1,2 1,3 1,,n
{
if((n-i+1)>=k)
{
if(a[j]>=m)
{
sum++;
}
}
else
{
break;
}
}
if(sum>=k) //此处却单单只执行了一次 1,,n
{
sum1++;
}
}
cout<<sum1<<endl;
return 0;
}
开始的思想,但是出现了问题,之前原来一直没理解此种遍历的所有子串意思,修改后的代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,k,sum1=0;
int a[2010];
signed main()
{
cin>>n>>m>>k;
for(int i=1; i<=n; i++)
{
cin>>a[i];
}
for(int i=1; i<=n; i++)
{
int sum=0; //字串中满足条件的个数
for(int j=i; j<=n; j++)
{
if(a[j]>=m)
{
sum++;
}
if(sum>=k) //长度检查
{
sum1+=(n-j+1); //后续所有子串满足
break;
}
}
}
cout<<sum1<<endl;
return 0;
}
3.小蓝的漆房
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t;
signed main()
{
cin>>t;
while(t--)
{
int n,k; //k区间就是滑块移动
int a[10010];
cin>>n>>k;
memset(a,0,sizeof(a));
for(int i=1; i<=n; i++)
{
cin>>a[i];
}
int min1=1e4;
for(int i=1;i<=60;i++) //暴力遍历所有可能
{
int sum=0,sign=1;
while(sign<=n)
{
if(a[sign]!=i)
{
sum++; //需要改漆
sign+=k; //滑块移动下一个位置
}
else
{
sign++; //滑块移动
}
}
min1=min(min1,sum);
}
cout<<min1<<endl;
}
return 0;
}
暴力遍历,区间问题,类似于滑块移动
4.美丽的区间
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,s;
int a[100010];
signed main()
{
cin>>n>>s;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int start=1,end=1,min_len=1e5+2,sum=0;
for(int end=1;end<=n;end++)
{
sum+=a[end];
while(sum>=s)
{
min_len=min(min_len,end-start+1);
sum-=a[start];
start++;
}
}
if(min_len!=(1e5+2))
{
cout<<min_len<<endl;
}
else
{
cout<<0<<endl;
}
return 0;
}
双指针遍历,优化时间复杂度
5.赛车游戏
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n;
int a[50010],b[50010];
signed main()
{
cin>>n;
for(int i=0; i<n; i++)
{
cin>>a[i]>>b[i];
}
sort(a,a+n);
sort(b,b+n);
int index=n-1,sum=0; //遍历小蓝
for(int i=n-1;i>=0;i--) //只能遍历小明,防止一直不满足的情况发生(和力扣分发饼干一个题)
{
if(index>=0 && a[i]<b[index]) //index>=0不要也行,有题目知道index>=0肯定满足
{
index--;
sum++;
}
}
cout<<sum<<endl;
return 0;
}
贪心+双指针方法
6.神奇的数组
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,sum=0;
int a[200010];
signed main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<=n;i++)
{
int temp=0,temp1=0;
for(int j=i;j<=n;j++)
{
temp^=a[j];
temp1+=a[j];
if(temp==temp1)
{
sum++;
}
}
}
cout<<sum<<endl;
return 0;
}
部分样例通过,时间复杂度超了,改为前缀思想+双指针
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,sum=0;
int a[200010],sum1[200010],sum2[200010];
signed main()
{
cin>>n;
for(int i=1; i<=n; i++)
{
cin>>a[i];
}
for(int i=1; i<=n; i++) //前缀思想
{
sum1[i]=a[i]^sum1[i-1];
sum2[i]=a[i]+sum2[i-1];
}
//双指针
int i=1,j=1;
while(i<=n&&j<=n)
{
if((sum1[i-1]^sum1[j])==(sum2[j]-sum2[i-1]))
{
sum+=j-i+1;
j++;
}
else
{
i++;
}
}
cout<<sum<<endl;
return 0;
}
((sum1[i-1]^sum1[j])==(sum2[j]-sum2[i-1])) 解释:
理解异或的本质和累积性
1. 异或的本质
异或(^)的本质是 模 2 加法,即 不带进位的二进制加法。
0 ^ 0 = 0
1 ^ 1 = 0
0 ^ 1 = 1
1 ^ 0 = 1
它与普通加法(+)不同,因为普通加法会发生进位,而异或不会。
2. 异或与普通加法关系的特殊条件
当一个序列从
a[i]
到a[j]
的 异或和 等于其 普通和 时,说明这个区间的所有数字相加时都 没有进位。
例如:数组
[2, 5, 3]
:
异或和 = 2 ^ 5 ^ 3 = 4
普通和 = 2 + 5 + 3 = 10
不满足等价条件,因为存在进位。
但对于特殊的情况,例如
[1,2,3]
:
异或和 = 1 ^ 2 ^ 3 = 6
普通和 = 1 + 2 + 3 = 6
满足等价条件,因为没有任何进位。即子序列 1 ^ 2 = 1 + 2
所以如果
[i, j]
没有进位,那么它的任意子序列也不会产生进位,所以可以直接计算得到: sum+=j-i+1;