acwing 22场周赛

A排位

传送门
题解:两个限定范围,前面至少有a人,那么就有n-a个空位,后面最多有b人,最多有b+1个情况(他本身和后面b个位置),这两者都要满足,我们取min即可
code:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <string.h>

using namespace std;

int main(){
    int t, n, a, b;
    cin >> t;
    while(t --){
        cin >> n >> a >> b;
        cout << min (n - a, b + 1) << endl;
    }
    return 0;
} 
//  2 1 1 3  1 1 1 1 1

B训练

传送门
题意:成为师傅,既要战斗力严格高于另一个人,这二人又不能有矛盾
题解:我们构造一个结构体,先按照战力排序,让第i个战力人的徒弟人数是前i-1个(若i-1战力和i相等,就一次依次往前找),之后我们回归到原始的顺序,再输入有矛盾的人的下标x,y,找出max(x,y)让战力的徒弟数减一就可
code:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <string.h>

using namespace std;

const int N = 2e5 +10;

typedef long long ll;

// num记录初始下标,sum记录可以成为多少个人的导师
struct node{
    int r,num,sum;
}a[N];

bool cmp1(node x, node y){
    return x.r < y.r;
}

bool cmp2(node x, node y){
    return x.num < y.num;
}

int main(){
    int n,k;
    cin >> n >> k;
   
    for (int i = 1; i <= n; i ++){
        cin >> a[i].r;
        a[i].num = i;
        a[i].sum = 0;
    }
    // 先按照战力排序
    sort(a+1,a+1+n,cmp1);
    // 如果i的战力高于i-1,那么可以让i-1人为徒弟,如果相等,只能等于i-1的情况
    for (int i = 2; i <= n; i ++){
        if(a[i].r > a[i - 1].r)
            a[i].sum = i - 1;
        else if (a[i].r == a[i - 1].r)
            a[i].sum = a[i - 1].sum;
    }
   
    int x, y;
    sort (a+1,a+1+n,cmp2);
    
    while (k --){
        cin >> x >> y;
        if (a[x].r > a[y].r) // 战力高但是存在矛盾,去掉这个徒弟
            a[x].sum --;
        else if (a[y].r > a[x].r)
            a[y].sum --;
    }
    
    for (int i = 1; i <= n; i ++)
        cout << a[i].sum << " ";
    
    return 0;
}

C构造数组

传送门
题意:求出两个数组有多少种可能,使得a[m]数组不严格单调递增,b[m]不严格单调递减,且a[i] <= b[i]
题解:我们可以看出,将b数组反转,那么整体就是个不严格单调递增数组,在1~n个数可重复地选取2m个数,结果对1e9 + 10 取余
这是一个经典组合数学问题,等价于把 2m个无区别的球放入 n 个有区别(因为数组有顺序)(因为数组有顺序)的盒子中,且允许空盒的方案数,这里第i 个盒子放的球就表示值为 i 的元素
因此问题就转化为,在1~n中,选取2m个数的方案
将第i个数的使用次数,设为Xi
那么就会有如下的方程:
X1+X2+…X(n-1)+X(n)=2m
设Yi=Xi+1,那么上述方程转化为
Y1+Y2+…Yn=2m+n
该转化可以确保我们有n-1个隔板,并且一定不会有两个隔板在同一位置,也就是隔板之间的球至少为1(原来答案为0,+1后就为1)
所以,在1~n中,选取2m个数的方案,就变成从2*m+n-1个位置里,插入n-1个隔板的方案数量
code:

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1e5 + 10, mod = 1e9 + 7;

typedef long long ll;

ll fact[N], infact[N];

ll fast(ll a, ll b, ll c){
    ll ans = 1;
    a %= c;
    while (b){
        if (b % 2) ans = ans * a % c;
        b /= 2;
        a = a * a % c;
    }
    return ans;
}


int main(){
    fact[0] = infact[0] = 1;
    for (int i = 1; i <= N; i ++){
        fact[i] = fact[i-1] * i % mod;
        infact[i] = infact[i-1] * fast(i,mod - 2, mod) % mod;
    }
    ll n, m;
    cin >> n >> m;
    cout << fact[2*m + n - 1] * infact[2*m] % mod * infact[n - 1] % mod;
    return 0;
}
posted @ 2021-10-27 17:00  Gsding  阅读(30)  评论(0)    收藏  举报