难度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;
}

C. Digital Logarithm

难度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;
}