A
图片说明
思路:这题我感觉写复杂了。
我的思路是贪心:尽可能让所有的战机拿到贡献,并且在当前这辆战机在可以拿的贡献中拿最大的。
那么,先对自己的战机和敌人的战机按照防御值升序。
然后枚举自己的所有战机,因为敌人的战机已经排序了,我们二分出最后一个小于当前这辆战机的位置,然后在区间[1,index]找最大值。
这就是一个区间最大值的问题了,可以用线段树来维护一下就行了。
代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<map>
#include<queue>
using namespace std;

const int maxn = 2e6 + 10;
typedef long long int ll;
struct node{
    ll d,v;
}s[maxn];
ll a[maxn];
bool cmp(ll x,ll y){
    return x < y;
}
bool cmp2(node x,node y){
    return x.d < y.d;
}
#define lson (rt * 2)
#define rson (rt * 2 + 1)
int pos;
ll m[maxn];
void build(int l,int r,int rt){
    if(l == r){
        m[rt] = s[pos ++].v;
        return ;
    }
    int mid = l + r >> 1;
    build(l,mid,lson);
    build(mid + 1,r,rson);
    m[rt] = max(m[lson],m[rson]);
}
ll query(int l,int r,int ql,int qr,int rt){
    if(l >= ql && r <= qr){
        return m[rt];
    }
    int mid = l + r >> 1;
    ll res = 0;
    if(ql <= mid)res = max(res,query(l,mid,ql,qr,lson));
    if(qr > mid)res = max(res,query(mid + 1,r,ql,qr,rson));
    return res;
}
void solved(){
    int n,m;scanf("%d%d",&n,&m);
    for(int i = 1; i <= n; i++)scanf("%lld",&a[i]);
    for(int i = 1; i <= m; i++)scanf("%lld",&s[i].d);
    for(int i = 1; i <= m; i++)scanf("%lld",&s[i].v);
    sort(a + 1,a + 1 + n,cmp);
    sort(s + 1,s + 1 + m,cmp2);
    pos = 1;
    build(1,m,1);
    ll ans = 0;
    for(int i = 1; i <= n; i++){
        int l = 1,r = m;
        int index = -1;
        while(l <= r){
            int mid = l + r >> 1;
            if(s[mid].d >= a[i]){
                r = mid - 1;
            }else{
                index = mid;
                l = mid + 1;
            }
        }
        if(index == -1)continue;
        ans += query(1,m,1,index,1);
    }
    printf("%lld\n",ans);
}
int main(){
    solved();
    return 0;
}

E
图片说明
思路:
先求出你和你朋友有多少个相同的题,那么你这个时候能对min(same,n - k)个,然后他错了几道题就意味着你对了几道题min(k,n - same)。
代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<map>
using namespace std;

const int maxn = 2e5 + 10;
typedef long long int ll;
bool you[maxn],f[maxn];
void solved(){
    int n,k;cin>>n>>k;
    for(int i = 1; i <= n; i++)cin>>you[i];
    for(int i = 1; i <= n; i++)cin>>f[i];
    int same = 0;
    for(int i = 1; i <= n; i++){
        if(you[i] == f[i])same++;
    }
    cout<<min(n - k,same) + min(k,n - same) <<endl;
}
int main(){
    solved();
    return 0;
}

G
图片说明
思路:
随便玩几个样例就发现规律了。
n = 1
0
1
n = 2
0 [0]
0 [1]
1 [1]
n = 3
0 [0 0]
0 [0 1]
0 [1 1]
1 [1 1]
dp[i][0] = dp[i - 1][0] + dp[i - 1][1]
dp[i][1] = 1
代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<map>
using namespace std;

const int maxn = 2e5 + 10;
typedef long long int ll;
ll mod = 998244353 ;
ll dp[maxn][2];
void solved(){
    int n;cin>>n;
    dp[1][0] = dp[1][1] = 1;
    for(int i = 2; i <= n; i++){
        dp[i][0] = (dp[i][0] + ((dp[i - 1][0] + dp[i - 1][1]) % mod)) % mod;
        dp[i][1] += 1;
    } 
    cout<<(dp[n][0] + dp[n][1]) % mod <<endl;
}
int main(){
    solved();
    return 0;
}

H
图片说明
思路:计算两个圆心距离,然后把外离与内含的情况去掉,其它均可。
代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<map>
using namespace std;

const int maxn = 2e5 + 10;
typedef long long int ll;
void solved(){
    ll x1,y1,r1,x2,y2,r2;
    scanf("%lld%lld%lld%lld%lld%lld",&x1,&y1,&r1,&x2,&y2,&r2);
    double d = sqrt(double((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)));
    if(d > r1 + r2){
        cout<<"NO"<<endl;return ;
    }
    if(d < abs(r1 - r2)){
        cout<<"NO"<<endl;return ;
    }
    cout<<"YES"<<endl;
}
int main(){
    int t;cin>>t;
    while(t--)
        solved();
    return 0;
}

D
图片说明
思路:
可以知道m次是固定的就非叶子节点的数,并且我们知道,每次大园林剪或者小园林剪都会把根节点的值覆盖掉,那么我们可以知道,根节点最后的生命力的值一定是来自叶子节点,即非叶子节点的值其实是无用的。
那么我们只需要那大最大的叶子节点的贡献即是答案,要拿到某个叶子节点的值需要满足dep[u] <= 大林园剪的次数(一路大林园剪上去)
大园林剪的次数 = n - 叶子节点 对 2 向上取整。
代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<map>
using namespace std;

const int maxn = 2e5 + 10;
typedef long long int ll;
ll G[maxn][2];
ll w[maxn];
int dep[maxn];
bool vis[maxn];
void dfs(int u,int de){
    if(u == 0)return ;
    dep[u] = de + 1;
    dfs(G[u][0],de + 1);
    dfs(G[u][1],de + 1);
}
void solved(){
    int n;scanf("%d",&n);
    int cnt = 0;
    for(int i = 1; i <= n; i++){
        int l,r;scanf("%d%d",&l,&r);
        G[i][0] = l;G[i][1] = r;
        if(l == r && l == 0)cnt++,vis[i] = true;
    }
    dfs(1,-1);
    int k = n - cnt;k = (k + 1) / 2;
    ll ans = 0;
    for(int i = 1; i <= n; i++){
        scanf("%lld",&w[i]);
        if(vis[i] && dep[i] <= k){
            ans = max(ans,w[i]);
        }
    }
    cout<<ans<<endl;
}
int main(){
    solved();
    return 0;
}