1. 程式人生 > 其它 >寒假訓練第十二天-Codeforces Round #697 (Div. 3)

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

技術標籤:寒假訓練c++

寒假訓練第十二天-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個數相等的數中取若干個數(前面已經選擇了多少數),即組合。由資料範圍觀察暴力記錄楊輝三角也行,下面給出楊輝三角和盧卡斯兩份程式碼。

//楊輝三角
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提升也不大,還是要把重心放到學演算法上,刷題成為輔助。