2019牛客多校第一场

A题

正解:笛卡尔树

师兄做法:二分/线段树, 首先二分答案,判断答案是否合法时,先找整个区间的最小值是否索引相同,再找最小值分成的两个小区间是否符合这样一直分下去。。。(写线段树好麻烦的说)

我做的暴力:从左到右,对于第i行查找后面第一个比该行数字小的下标,相同就继续第i+1行,不相同则说明后面的那几行不满足条件删去

#include
using namespace std;
 
const int maxn = 1e5 + 10;
int n,cnt;
int a[maxn],b[maxn];
 
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i = 0;i < n; ++i) scanf("%d",&a[i]);
        for(int i = 0;i < n; ++i) scanf("%d",&b[i]);
        cnt = n - 1;
        for(int i = 0;i <= cnt; ++i)
        {
            for(int j = i + 1;j <= cnt; ++j)
            {
                int f = 0;
                if(a[i] > a[j]) f++;
                if(b[i] > b[j]) f++;
                if(f == 2) break;
                if(f == 1)
                {
                    cnt = j - 1;
                    break;
                }
            }
        }
        printf("%d\n",cnt + 1);
    }
    return 0;
}

B题

贼坑啊,开始就没看懂样例啥意思。。。后来跟着题解推ci推了n久也。。。没推出来(只能背过)

然后发现还有个取倒数再取模(有人写的递推法求逆元)

2019牛客多校第一场_第1张图片

#include
using namespace std;

typedef long long ll;
const int p = 1e9 + 7;

ll a[1005];
int n;

ll inv(ll b)  //递推法求逆元
{
    if(b == 1) return 1;
    return p - p / b * inv(p % b) % p;
}

int main()
{
    while(~scanf("%d",&n))
    {
        for(int i = 1;i <= n;i++) scanf("%lld",&a[i]);
        ll ans = 0;
        for(int i = 1;i <= n;i++)
        {
            ll res = 1;
            for(int j = 1;j <= n;j++)
            {
                if(i == j) continue;
                res = (res * (a[j] * a[j] % p - a[i] * a[i] % p + p) % p) % p;
            }
            res = res * 2 * a[i] % p;
            res = inv(res);
            ans = (res + ans) % p;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

E题

这个题首先会想到求方案数,动态规划或者组合数之类的

不过确实不好推情况太多了

最后借鉴题解

令f[i][j]为有i个A,j个B的合法方案数

当有i - j < n时,说明还没有凑齐n个AB,要满足有n个AB,A在前面的数量还不够,所以后面可以放A
f[i + 1][j] = f[i][j] + f[i + 1][j];

当有j - i < m时,说明还没有凑齐m个BA,要满足有m个BA,B在前面的数量还不够,所以后面可以放B
f[i][j + 1] = f[i][j] + f[i][j + 1];

/*
令f[i][j]为有i个A,j个B的合法方案数

当有i - j < n时,说明还没有凑齐n个AB,要满足有n个AB,A在前面的数量还不够,所以后面可以放A
f[i + 1][j] = f[i][j] + f[i + 1][j];

当有j - i < m时,说明还没有凑齐m个BA,要满足有m个BA,B在前面的数量还不够,所以后面可以放B
f[i][j + 1] = f[i][j] + f[i][j + 1];
*/

 #include
 using namespace std;

 const int p = 1e9 + 7;
 int n,m;
 int f[2010][2010];

 int main()
 {
     while(~scanf("%d%d",&n,&m) && (n + m))
     {
         for(int i = 0;i <= n + m; ++i)
            for(int j = 0;j <= n + m; ++j)
                f[i][j] = 0;
        f[0][0] = 1;
        for(int i = 0;i <= n + m; ++i)
            for(int j = 0;j <= n + m; ++j)
            {
                if(i - j < n) f[i + 1][j] = (f[i][j] + f[i + 1][j]) % p;
                if(j - i < m) f[i][j + 1] = (f[i][j] + f[i][j + 1]) % p;
            }
        printf("%d\n",f[n + m][n + m]);
     }
     return 0;
 }

F题

瞎猜的,没想到猜对了hhh

证明挺麻烦的,几何法和积分都能做(反正我都不会做。。。。)

https://blog.csdn.net/Izayoi_w/article/details/96475077

你可能感兴趣的:(赛后补题)