难度1200
题意:给定一个n阶楼梯的高度和可以跨的高度,求最高能走到多高。
思路:思路其实很简单 去找到最大的可以去到的台阶就行了 那么前缀和就是答案了 然后数据范围暴力是肯定不行的 再去想一下 一般求最大满足 最小满足的题目一般都是二分 那么就可以去想想可不可以二分了 这题明显是可以二分的 去维护一个前缀最大值数组就可以二分这个数组了 二分出来的答案就是最大可以到达的最大台阶了
然后有一个小细节 二分的 l 应该从0开始 因为可能会有一个台阶都不能跨的
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int a[N];
int b[N];
long long sum[N];
void solve()
{
int n,q;
cin>>n>>q;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
{
sum[i]=sum[i-1]+a[i];
b[i]=max(b[i-1],a[i]);
}
while(q--)
{
int k;
cin>>k;
int l=0,r=n;
while(l<r)
{
int mid=l+r+1>>1;
if(b[mid]>k) r=mid-1;
else l=mid;
}
cout<<sum[l]<<" ";
}
puts("");
}
int main()
{
int t;
cin>>t;
while(t--)
solve();
return 0;
}
难度1300
题意: 一个聚会要从n 个人中邀请一部分人,如果第 i 个人未被邀请,将会获得不高兴值 a[i] 。这 n 个人中有 m 对朋友,每对朋友来了以后,都会吃一个蛋糕。要求吃的蛋糕的数量必须为偶数,求这种条件下的最小不高兴值
思路:由于可以很直接的看出当m为偶数的时候 可以邀请所有人 所以m为偶数的时候一定为0
那既然考虑偶数了 是不是也要考虑一下奇数 如果当m为奇数的时候会有什么操作呢?当m是奇数的时候,我们证明:最多只有两个人无法到场。
为了让边数变回偶数,我们需要删除一些人,记录所有人的度:
那么我们去删除一些人 是不是从删除一个人开始呢?
1.删除一个人 删除一个人使得度数的总和是满足题目要求的,那么删掉的一定是奇数关系的人
2.删除两个人 删除两个人就有几种选择了
(1)删除一个奇数的度的点再删除一个偶数的度的点这样明显不比 1 好 所以直接放弃
(2)删除一个奇数和不与他相邻的奇数 这样会删除偶数个点 放弃
(4)删除一个奇数点和与他相邻的奇数点 这样不比 1 好 放弃
(3)删除一个偶数点和偶数点并且是相邻的 如果不相邻 就不可能删除奇数的边 这种方法是没被统计过的
3.删除三个人及以上是没有办法比删除一个人和两个人的花费能小的 因为删除两个人就一个能构造出一组最小合法解了 删除三个及以上都是在前两个操作上增加花费
上面全部操作取一个min就好了
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int d[N];
int u[N],v[N];
int a[N];
void solve()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
memset(d,0,sizeof d);
for(int i=1;i<=m;i++)
{
int a,b;
cin>>a>>b;
u[i]=a,v[i]=b;
d[a]++,d[b]++;
}
if(m%2==0)
{
cout<<0<<endl;
return ;
}
int minl=0x3f3f3f3f;
for(int i=1;i<=n;i++)
if(d[i]%2)
minl=min(minl,a[i]);
for(int i=1;i<=m;i++)
{
if(d[u[i]]%2==0&&d[v[i]]%2==0)
{
minl=min(minl,a[u[i]]+a[v[i]]);
}
}
cout<<minl<<endl;
return ;
}
int main()
{
int t;
cin>>t;
while(t--)
solve();
return 0;
}
难度1400
题意:给定两个长度为n的正整数数组a,b,每次操作可以选择任意一个数,转换为其十进制的位数。问至少多少次操作,可以让a,b相似。即通过排序后,两个数组相等
思路:首先可以知道只有大的可以变成小的 小的是不可以变成大的 那么我A序列的最大值只能去和B序列中的比A序列的最大值大的数去匹配 B序列的最大值只能去和A序列中的比B序列的最大值大的数去匹配 如果说两个序列的最大值不相等会有什么情况? 那么这两个序列的最大值的比较大的那个值 肯定是没东西和他匹配的 而这个数一定是要变小的 所以一定要进行上面的操作
那么经过这样的想法是不是诞生了一个贪心想法 是不是如果两个序列的最大值不相同 那么每一步都去让最大值中的那么比较大的去变小 这样的答案一定是有解的但是是不是最优的呢?答案是最优的 因为每次操作都是变的两个序列的最大值 而最大值是一定要去变小的 这样是没有浪费的操作的 所以是最优的
实现的时候用两个优先队列去维护就ok了
#include <bits/stdc++.h>
using namespace std;
int f(int x)
{
int res=0;
while(x)
{
res++;
x/=10;
}
return res;
}
void solve()
{
int n;
priority_queue<int,vector<int>> a,b;
cin>>n;
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
a.push(x);
}
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
b.push(x);
}
int ans=0;
while(a.size())
{
if(a.top()==b.top())
{
a.pop(),b.pop();
}
else if(a.top()>b.top())
{
int x;
x=a.top();
a.pop();
a.push(f(x));
ans++;
}
else
{
int x;
x=b.top();
b.pop();
b.push(f(x));
ans++;
}
}
cout<<ans<<endl;
return ;
}
int main()
{
int t;
cin>>t;
while(t--)
solve();
return 0;
}