牛客周赛 Round 60

A-困难数学题

思路

\(x\) \(xor\) \(x\) \(xor\) \(x\) \(xor\) \(x\),异或有结合律,\(x\) \(xor\) \(x\) \(= 0\)\(0\) \(xor\) \(0\) \(= 0\),所以本题直接输出0。

代码

#include <iostream>

using namespace std;

int main()
{
    int x;
    cin >> x;
    cout << 0;
    
    return 0;
}

B-构造序列

思路

正数负数各取一个构造序列,直至某一个值消耗。可以知道,如果正数负数个数之差不超过1,直接输出 \(n + m\) 即可,超过1,则取较少的那个值乘2+1。

代码

#include <iostream>

using namespace std;

int main()
{
    int n, m;
    cin >> n >> m;
    
    if (abs(n - m) > 1) cout << min(n, m) * 2 + 1;
    else cout << n + m;
    
    return 0;
}

C-连点成线

思路

题意是求在一行或一列中最大差是多少。可以分别存 \(x,y\) 坐标,再分别跑 \(n\) 行和列,暴力求该行或列的最大差,取一个max值。时间复杂度为\(O(nmlogm)\),但有些行或列是可以不用求的,比如该行或列没有点或只有一个点。

代码

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

const int N = 1e5 + 10;

int n, m;
vector<int> gx[N], gy[N];

int main()
{
    cin >> n >> m;
    
    for (int i = 0; i < m; i ++)
    {
        int x, y;
        cin >> x >> y;
        
        gx[x].push_back(y);
        gy[y].push_back(x);
    }    
    
    int res = 0;
    for (int i = 1; i <= n; i ++)
    {
        if (gx[i].size() > 1) {
            sort(gx[i].begin(), gx[i].end());
            res = max(res, gx[i].back() - gx[i].front());
        }
        if (gy[i].size() > 1) {
            sort(gy[i].begin(), gy[i].end());
            res = max(res, gy[i].back() - gy[i].front());
        }
    }
    
    cout << res;
    
    return 0;
}

D-我们N个真是太厉害了

思路

题目大意:给出的n个数是否可以组合1~n以内所有的数。
我的写法假了,但这题没卡,就是考虑dp,大小为i的数是否可以被构成,典型的01背包,但时间复杂度超了,我用了bitset进行优化。

代码

#include <iostream>
#include <bitset>

using namespace std;

const int N = 1e5 + 10;

int n;

void solve()
{
    cin >> n;
    bitset<N> st;
    st[0] = 1;
    for (int i = 0; i < n; i ++)
    {
        int x;
        cin >> x;
        st |= (st << x);
    }
    int res= 0;
    for (int i = 1; i <= n; i ++)
    {
        if (!st[i]) {
            res = i;
            break;
        }
    }
    if (!res) cout << "Cool!" << '\n';
    else cout << res << '\n';
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    
    int t;
    cin >> t;
    while (t --) solve();
    
    return 0;
}

真思路

将n个数排序后,前i项和\(s_i\)与第i+1项数\(a_{i+1}\)差值不超过1,那么1~\(s_i + a_{i+1}\)是可以被组成的。很容易思考,首先\(s_1\)必等于1,因为必须保证第一位要可组成,而组成1的数只有1,则在第二位,在满足第一位与第二位差值不超1的条件下2或3一定被组成,以此类推,第i个数时数值i一定可以组成,且前i项和也可被组成。

代码

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;

const int N = 1e5 + 10;

int n;
ll a[N];

void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i ++) cin >> a[i];
    sort(a + 1, a + 1 + n);
    ll sum = 0;
    for (int i = 1; i <= n; i ++)
        if (sum >= n) break;
        else if (sum + 1 < a[i]) {
            cout << sum + 1 << '\n';
            return ;
        }
        else sum += a[i];
    if (sum < n) {
        cout << sum + 1 << '\n';
        return ;
    }
    cout << "Cool!" << '\n';
}

int main()
{
    int t;
    cin >> t;
    while (t --) solve();
    
    return 0;
}

E-折返跑

思路

组合数
n个点,两个杆一开始在1和n上,要绕杆跑m趟,每次可操作一次将左杆右移或右杆左移,在m趟后保证左右杆的方位不变。在去除1和n两个点后剩下n-2个点可以操作,但要求必须操作m-1次(最后一趟到达终点不必在操作),相当于将n-2个球取m-1次,求有多少种取法。那就是C(n-2, m-1)。
因为常规组合数写法是\(O(n^2)\)的,这里必须进行预处理优化,再用公式一步算出。
牛客题解给的组合数封装板子

代码

#include <iostream>

using namespace std;

typedef long long ll;

const int M = 1e6 + 10;
const int mod = 1e9 + 7;

int n, m;
ll fact[M + 10], infact[M + 10];

ll qmi(int a, int b)
{
    ll res = 1;
    while(b)
    {
        if(b & 1) res = res * a % mod;
        a = (ll)a * a % mod;
        b >>= 1;
    }
    return res;
}

void init()
{
    fact[0] = infact[0] = 1;
    for(int i = 1; i <= M; i ++) fact[i] = fact[i - 1] * i % mod;
    infact[M] = qmi(fact[M], mod - 2);
    for(int i = M - 1; i >= 1; i --) infact[i] = infact[i + 1] * (i + 1) % mod;
}

int C(int a, int b)
{
    if(b < 0 || a - b < 0) return 0;
    return fact[a] * infact[b] % mod * infact[a - b] % mod;
}

void solve()
{
    cin >> n >> m;
    cout << C(n - 2, m - 1) << '\n';
}

int main()
{
    init();
    
    int t;
    cin >> t;
    
    while (t --) solve();
    
    return 0;
}

F-口吃

牛客官方题解

代码

#include <iostream>

using namespace std;

typedef long long ll;

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

int n;
ll a[N], b[N], s[N];
ll f[N];

ll qmi(ll a, ll b)
{
    ll res = 1;
    while (b)
    {
        if (b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}

ll inv(ll x) 
{
    return qmi(x, mod - 2);
}

int main()
{
    cin >> n;
    for (int i = 1; i < n; i ++) cin >> a[i];
    for (int i = 1; i < n; i ++) cin >> b[i];
    for (int i = 1; i < n; i ++) s[i] = (a[i] + b[i]) % mod;
    
    f[1] = s[1] * inv(a[1]) % mod;
    ll res = f[1];
    for (int i = 2; i < n; i ++)
    {
        f[i] = (b[i] * b[i] % mod * f[i - 1] % mod + s[i] * s[i] % mod) % mod * inv(a[i] * a[i] % mod) % mod;
        res = (res + f[i]) % mod;
    }
    
    cout << res + 1;
    
    return 0;
}
posted @ 2024-09-16 01:29  Natural_TLP  阅读(66)  评论(0)    收藏  举报