acwing第二十二场周赛题解

1 排位

有 n 个人排成了一队,小明就在其中。

他不知道自己的确切排位,但是他能确定的是,排在他前面的人不少于 a 个,排在他后面的人不超过 b 个。

请问,对于他的具体排位,一共有多少种可能性?

输入格式
第一行包含整数 T,表示共有 T 组数据。

每组数据占一行,包含三个整数 n,a,b。

输出格式
每组数据输出一行结果,一个整数,表示小明具体排位的可能数量。

数据范围
本题共两个测试点。
小测试点,如样例所示。
大测试点满足:1≤T≤50,0≤a,b<n≤100。

输入样例:
2
3 1 1
5 2 3
输出样例:
2
3
此题思路
首先排在小明前面的人至少要有a人,所以小明在区间[a+1,n];
其次在小明后面的人不超过b人,所以小明在区间[n-b,b]。
取两个区间的交集就是小明可能在的区间。

#include<bits/stdc++.h>
using namespace std;
int main(){
    int t;
    cin>>t;
    while(t--){
        int n,a,b;
        cin>>n>>a>>b;
        cout<<min(n-a,b+1)<<endl;
    }
    return 0;
}

2 训练

达尔星有 n 个强大的下级战士,编号 1∼n。

其中第 i 名战士的战斗力为 ri。

战士 a 可以成为战士 b 的战斗导师,当且仅当 ra>rb 且两人之间不存在矛盾。

给定每个战士的战斗力值以及战士之间存在的 k 对矛盾关系。

请你计算,每个战士可以成为多少战士的战斗导师。

输入格式
第一行包含两个整数 n 和 k。

第二行包含 n 个整数 r1,r2,…,rn。

接下来 k 行,每行包含两个整数 x,y,表示战士 x 和战士 y 之间存在矛盾。同一对矛盾关系不会在输入中重复给出,即出现了 x,y 以后,后面就不会再次出现 x,y 或 y,x。

输出格式
共一行,n 个整数,表示每个战士可以作为战斗导师的战士数量。

数据范围
前三个测试点满足,2≤n≤10,0≤k≤10。
所有测试点满足,2≤n≤2×105,0≤k≤min(2×105,n(n−1)2),1≤ri≤109,1≤x,y≤n,x≠y。

输入样例:
4 2
10 4 10 15
1 2
4 3
输出样例:
0 0 1 2

思路如下
首先将战士按战斗力从大到小排序,记录每个战士与其有矛盾且战斗力比他低的战士数量,排序之后,先不考虑矛盾关系,每个战士可以作为编号比他靠后的战士的导师(当然不包括战斗力和他相等的战士)。
矛盾关系很好处理
现在就要解决战斗力和该战士相等的编号最大的战士
要解决这个战士的编号,可以使用二分。
此时时间复杂度还是 O(nlog2n)。

#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
const int ll = 5e5;
int n, k;
struct node {
    int bh, r;
    int k;
    int res;
}a[ll];
int cmp1(node x, node y) {
    return x.r > y.r;
}
int cmp2(node x, node y) {
    return x.bh < y.bh;
}
int main() {
    cin >> n >> k;
    for (int i = 1; i <= n; i++) {
        cin >> a[i].r;
        a[i].bh = i;
        a[i].k = 0;
    }
    for (int i = 1; i <= k; i++) {
        int x, y;
        cin >> x >> y;
        if (a[x].r > a[y].r)
            a[x].k++;
        if (a[x].r < a[y].r)
            a[y].k++;
    }
    sort(a + 1, a + n + 1, cmp1);

    for (int i = 1; i <= n; i++) {
        int l = 1, r = n, z = a[i].r;
        while (l < r) {
            int mid = (l + r +1) / 2;
            if (a[mid].r >= z) l = mid;
            else r = mid -1;
        }
        a[i].res = n - l - a[i].k;
    }
    sort(a + 1, a + n + 1, cmp2);
    for (int i = 1; i <= n; i++)
        cout << a[i].res << " ";
    return 0;
}

4 构造数组

现在需要构造一对数组 (a,b),要求:

数组 a 和数组 b 的长度都为 m。
两个数组中的元素的取值范围都是 [1,n]。
∀i∈[1,m],ai≤bi。
数组 a 中元素非严格单调递增。
数组 b 中元素非严格单调递减。
请问,共能构造出多少对满足条件的数组?

输出对 10^9+7 取模后的结果。

输入格式
一行,两个整数 n,m。

输出格式
一个整数,表示满足条件的数组对的数量对 10^9+7 取模后的结果。

数据范围
前三个测试点满足,1≤n,m≤10。
所有测试点满足,1≤n≤1000,1≤m≤10。

输入样例:
2 2
输出样例:
5
算法 DP
提取出两个关键维度来设计状态转移方程
第一维是数组的长度
第二维是该数组最后一个数字的大小。
对于a数组fa[i][j]= ∑ k = 1 j \sum_{k=1}^j k=1jfa[i-1][k]
对于b数组fb[i][j]= ∑ k = j n \sum_{k=j}^n k=jnfb[i-1][k]
对于长度为m,数字范围为[1,n]的数组
想要知道数组对的数量,就需要枚举两个数组的分界点。
ans= ∑ i = 1 n \sum_{i=1}^n i=1n(fa[m][i] * ∑ j = i n \sum_{j=i}^n j=infb[m][j]);
对于b数组的求和可以用前缀和来优化。

#include<iostream>
using namespace std;
const long long p = 1e9 + 7;
long long fa[20][2000], fb[20][2000];
long long ans;
long long a[2000], b[2000];
int main() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        fa[1][i] = 1;
        fb[1][i] = 1;
    }
    for (int i = 2; i <= m; i++)
        for (int j = 1; j <= n; j++)
            for (int k = n; k >= j; k--)
                fb[i][j] = (long long)(fb[i][j] + fb[i - 1][k]) % p;

    for (int i = 2; i <= m; i++)
        for (int j = 1; j <= n; j++)
            for (int k = 1; k <= j; k++)
                fa[i][j] = (long long)(fa[i][j] + fa[i - 1][k]) % p;

    for (int i = 1; i <= n; i++) {
        a[i] = fa[m][i];
        b[i] = fb[m][i];
    }
    for (int i = 1; i <= n; i++) 
        b[i] = (long long)(b[i] + b[i - 1]) % p;
    
    for (int i = 1; i <= n; i++)
        ans = (ans + (long long)(a[i] * (b[n] - b[i - 1])) % p) % p;
    cout << ans;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值