寒假训练第十二天-Codeforces Round #697 (Div. 3)

寒假训练第十二天-Codeforces Round #697 (Div. 3)

前言:心态出了些问题就鸽了两天,还是继续训练吧。打了一场div3,然后就unrated了,发挥也挺糟糕的。

题目链接-https://codeforces.com/contest/1475

A-Odd Divisor

题意:问一个数是否有大于1的奇因子。

题解:很明显奇数肯定有奇因子(本身),偶数则有两种情况一种是2^d不含奇因子的,其他的则必定含奇因子(一直除以2肯定会出现奇数)。

int32_t main()
{
    
    
    ICO;
    ll t, n;
    cin >> t;
    while(t--)
    {
    
    
        cin >> n;
        if(n & 1) cout << "YES" << endl;
        else
        {
    
    
            if(n & (n - 1)) cout << "YES" << endl;
            else cout << "NO" << endl;
        }
    }
    return 0;
}

B-New Year’s Number

题意:给你一个数,问是否可以拆成n * 2020 + m * 2021(n,m可为0)。

题解:暴力标记所有可拆成n * 2020 + m * 2021的数,然后O(1)查询即可。

const int maxn = 1e6 + 10;
bool ok[maxn];
int32_t main()
{
    
    
    ICO;
    ll t, n;
    for(int i = 0; i <= 1000; i++)
    {
    
    
        for(int j = 0; j <= 1000; j++)
        {
    
    
            int a = 2020 * i + j * 2021;
            if(a > 1000000) continue;
            ok[a] = 1;
        }
    }
    cin >> t;
    while(t--)
    {
    
    
        cin >> n;
        if(ok[n]) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
    return 0;
}

C-Ball in Berland

题意:给你n组数,每组数有两个数(第一个数和第二个数),现让你从n组数中任选两组,需要保证选择的两组中每一组和第二组的第一个数和第一个数不同,第二个数和第二个数不同(第一个数可以和第二个数相同)。问你有多少种选择的方案,输出方案数。

题解:我们可以先以第一个数为基准求出所有的方案数,然后我们去考虑第二个数相同造成的影响,再减去影响即可。

const int maxn = 2e5 + 10;
int ok1[maxn], book[maxn], ok2[maxn];
ll c[maxn];
int32_t main()
{
    
    
    ICO;
    for(int i = 1; i <= 200000; i++)
        c[i] = i * (i - 1) / 2;
    int t, n;
    cin >> t;
    while(t--)
    {
    
    
        int a, b, k, x;
        cin >> a >> b >> k;
        for(int i = 1; i <= k; i++)
        {
    
    
            cin >> x;
            ok1[x]++;
        }
        ll sum = 0, res = 0;
        for(int i = 1; i <= a; i++)
        {
    
    
            book[i] = ok1[i] * (k - ok1[i]) - sum * ok1[i];
            sum += ok1[i];
            res += book[i];
        }
        for(int i = 1; i <= k; i++)
        {
    
    
            cin >> x;
            ok2[x]++;
        }
        for(int i = 1; i <= b; i++) {
    
    if(ok2[i] > 1) res -= (c[ok2[i]]);}
        cout << res << endl;
        for(int i = 1; i <= a; i++) ok1[i] = book[i] = 0;
        for(int i = 1; i <= b; i++) ok2[i] = 0;
    }
    return 0;
}

D-Cleaning the Phone

题意:一个东西有两个属性:价值和代价。现在有n件物品,给你一个最小价值的限制,问满足次限制的最小代价是多少。

题解:由题意我们发现代价只有1和2,那我们就按代价将价值分成两份(a 和 b),然后贪心去处理(要排序),贪心的准则为:开始先取a中的所有物品,b的物品都不取,然后放弃a中价值最小的去取b中价值最大的(一直取直到满足限制再记录代价),循环往复,直至a中物品全被丢弃,输出此过程中最小代价即可。

const int maxn = 2e5 + 10;
int a[maxn], b[maxn];
vector<int> v1, v2;
int32_t main()
{
    
    
    ICO;
    int t, n, m;
    cin >> t;
    while(t--)
    {
    
    
        cin >> n >> m;
        ll sum = 0;
        for(int i = 1; i <= n; i++) {
    
    cin >> a[i]; sum += a[i];}
        for(int i = 1; i <= n; i++) cin >> b[i];
        if(sum < m) {
    
    cout << -1 << endl; continue;}
        for(int i = 1; i <= n; i++)
        {
    
    
            if(b[i] == 1) v1.push_back(a[i]);
            else v2.push_back(a[i]);
        }
        sort(v1.rbegin(), v1.rend());
        sort(v2.begin(), v2.end());
        sum = 0;
        for(int i = 0; i < v2.size(); i++) sum += v2[i];
        int p = 0, res = inf_int;
        for(int i = 0; i <= v2.size(); i++)
        {
    
    
            while(p < v1.size() && sum < m) sum += v1[p++];
            if(sum >= m) res = min(res, (int (v2.size() - i) << 1) + p);
            if(i < v2.size())sum -= v2[i];
        }
        cout << res<< endl;
        v1.clear(), v2.clear();
    }
    return 0;
}

E-Advertising Agency

题意:从n个数中选择k个数,使权值最大,问选择方案数(取模后)。

题解:我们将权值从大到小排序,很明显方案数是和第k个数相等的数的个数决定的,则我们需要求的就是从所有和第k个数相等的数中取若干个数(前面已经选择了多少数),即组合。由数据范围观察暴力记录杨辉三角也行,下面给出杨辉三角和卢卡斯两份代码。
卢卡斯代码出处:https://www.cnblogs.com/fzl194/p/9095177.html

//杨辉三角
const int maxn = 1e3 + 10;
const int mod = 1e9 + 7;

int a[maxn], ok[maxn];
int c[maxn][maxn];
 
int32_t main()
{
    
    
    ICO;
    c[0][0] = 1;
    for(int i = 1; i <= 1000; i++)
    {
    
    
        c[i][0] = 1;
        for(int j = 1; j <= i; j++)
            c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
    }
    int t, n, k;
    cin >> t;
    while(t--)
    {
    
    
        cin >> n >> k;
        for(int i = 1; i <= n; i++) {
    
    cin >> a[i]; ok[a[i]]++;}
        sort(a + 1, a + 1 + n, greater<int>() );
        int cnt = 0;
        for(int i = 1; i <= k; i++)
            if(a[i] == a[k]) {
    
    cnt = i - 1; break;}
        ll res = c[ok[a[k]]][min(k - cnt, ok[a[k]] - (k - cnt))];
        cout << res << endl;
        for(int i = 1; i <= n; i++) ok[a[i]] = 0;
 
    }
    return 0;
}

//卢卡斯
const int maxn = 1e3 + 10;
const int mod = 1e9 + 7;

ll pow(ll a, ll b, ll m)
{
    
    
    ll ans = 1;
    a %= m;
    while(b)
    {
    
    
        if(b & 1)ans = (ans % m) * (a % m) % m;
        b /= 2;
        a = (a % m) * (a % m) % m;
    }
    ans %= m;
    return ans;
}
ll inv(ll x)
{
    
    
    return pow(x, mod - 2, mod);
}
ll C(ll n, ll m)
{
    
    
    if(m > n)return 0;
    ll up = 1, down = 1;
    for(int i = n - m + 1; i <= n; i++)up = up * i % mod;
    for(int i = 1; i <= m; i++)down = down * i % mod;
    return up * inv(down) % mod;
}
ll Lucas(ll n, ll m)
{
    
    
    if(m == 0)return 1;
    return C(n % mod, m % mod) * Lucas(n / mod, m / mod) % mod;
}

int a[maxn], ok[maxn];
int32_t main()
{
    
    
    ICO;

    int t, n, k;
    cin >> t;
    while(t--)
    {
    
    
        cin >> n >> k;
        for(int i = 1; i <= n; i++) {
    
    cin >> a[i]; ok[a[i]]++;}
        sort(a + 1, a + 1 + n, greater<int>() );
        int cnt = 0;
        for(int i = 1; i <= k; i++)
            if(a[i] == a[k]) {
    
    cnt = i - 1; break;}
        ll res = Lucas(ok[a[k]], min(k - cnt, ok[a[k]] - (k - cnt)));
        cout << res << endl;
        for(int i = 1; i <= n; i++) ok[a[i]] = 0;
    }
    return 0;
}

总结:感觉打了两周cf提升也不大,还是要把重心放到学算法上,刷题成为辅助。

猜你喜欢

转载自blog.csdn.net/Siyue1999/article/details/113171938
今日推荐