牛客小白月賽101 A~E

nannandbk發表於2024-10-08

牛客小白月賽101 A~E

A-tb的區間問題

題意:tb 給了 fc 一個長度為 n 的陣列 A, fc 對 A 進行 k 次如下操作:

刪除陣列第一個元素或者刪除陣列最後一個元素。

求最後得到的陣列和的最大值。

思路:最後刪除的是某一組前字尾,一一去列舉可行的區間即可。

// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;

ll a[N],s[N];

int main()
{
    ios::sync_with_stdio(false);   cin.tie(nullptr), cout.tie(nullptr);
    int n,k; cin>>n>>k;
    for(int i = 1;i <= n; i++)
        cin>>a[i];
    for(int i = 1;i <= n; i++)
        s[i] = s[i-1] + a[i];
    int len = n-k;
    ll ans = 0;
    for(int i = 1;i <= n; i++)
    {
        if(i-len+1 >= 1){
            ans = max(ans,s[i]-s[i-len]);
        }
    }
    cout<<ans<<"\n";
    return 0;
}

B-tb的字串問題

題意:tb 給了 fc 一個字串。

fc 對字串可以進行若干次 (可能是0) 次如下操作:

選擇子串 ''fc'' 或者子串 ''tb'' ,將其從字串中刪去。

求最後剩下字串的最短長度。

子串:原字串中下標連續的一段字串。

思路:能刪我們肯定刪呀,而且"fc"和"tb"也沒有共同字母也沒有干擾。我們可以用棧去維護,類似括號匹配那種。

// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;

int main()
{
    ios::sync_with_stdio(false);   cin.tie(nullptr), cout.tie(nullptr);
    int n; cin>>n;
    string s; cin>>s;
    s = "?" + s;
    stack<char>st;
    for(int i = 1;i <= n; i++)
    {
        
        if(st.size() > 0){
            char x = st.top();
            char now = s[i];

            if((x=='f'&&now=='c')||(x=='t'&&now=='b'))
                st.pop();
            else st.push(now);
        }else st.push(s[i]);      
    }

    cout<<st.size()<<"\n";



    return 0;
}

/*
12
tfffffcccccb
*/

C-tb的路徑問題

題意:tb 給了 fc 一張有 \(n \times n\)個格點的圖。 圖上每個格點都寫著一個數。第 \(i\) 行第\(j\)列的格點上寫著的數字為 \(i\)\(j\)的最大公約數。 現在 fc 需要從第 1行第 1 列出發,去往第 n 行第 n 列處的格點,fc 可以消耗一點能量移向相鄰的格點。 在任何時,設 fc 所位於的格點上所寫的數字為 x ,如果 x 不為 1 ,他可以使用傳送陣傳送到任何數字為 x 的格點,此操作不消耗能量。求 fc 到達第 n行第 n列所消耗的最少能量。

相鄰:如果用 (x,y) 表示第 x行第 y 列的位置,(x,y) 與 (x+1,y),(x,y+1),(x−1,y),(x,y−1)(x+1,y) 相鄰。

思路:我們發現對角線的數字都是每個數字第一次出現的位置,就算要瞬移也要先到這裡。那麼我們考慮列舉先到哪個數字,然後瞬移到距離(n,n)最近的地方,再一步步走即可。

// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;

int main()
{
    ios::sync_with_stdio(false);   cin.tie(nullptr), cout.tie(nullptr);
    int n; cin>>n;
    ll ans = (n-1)*2;
    for(int i = 2;i <= n; i++)
    {
        int x = i,y = i;
        x = n/i*i;
        y = (x-1)/i*i;

        ll t = (i-1)*2;
        if(y > 0)
            t += (n-x)+(n-y);
        else t += (n-i)*2;

        ans = min(ans,t);

        // cout<<"x = "<<x<<" y = "<<y<<" t = "<<t<<"\n";
    }

    cout<<ans<<"\n";


    return 0;
}

D-tb的平方問題

題意:tb 給了 fc 一個陣列 A 。
隨後, tb 對 fc 進行了 q 次詢問,每次詢問 tb 給 fc 一個 x,需要 fc 給出包含了 x 位置且區間和為完全平方數的連續子陣列個數。
完全平方數:存在正整數 t ,滿足\(t \times t = x\) ,則稱 x 為完全平方數
連續子陣列:原陣列中某段下標連續的元素按原順序構成的陣列。

思路:可以先求個字首和,然後列舉區間,如果是完全平方數那麼這段區間的貢獻加1。對於區間加很容易想到差分。

// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 3100;

int s[N],d[N],a[N];

int main()
{
    ios::sync_with_stdio(false);   cin.tie(nullptr), cout.tie(nullptr);
    
    int n,q; cin>>n>>q;
    for(int i = 1;i <= n; i++){
        cin>>a[i];
        s[i] = s[i-1] + a[i];
    }

    for(int i = 1;i <= n; i++)
    {
        for(int j = i;j <= n; j++)
        {
            int l = i,r = j;
            int t = s[r]-s[l-1];
            int tt = sqrt(t);
            if(tt*tt == t)
                d[l]+=1,d[r+1]-=1;
        }
    }

    for(int i = 1;i <= n;i++)
        d[i]+=d[i-1];
    while(q--)
    {
        int x; cin>>x;
        cout<<d[x]<<"\n";
    }

    return 0;
}

E-tb的數數問題(調和級數)

題意:tb 給了 fc 一個包含若干個數字的可重集合 A ,如果我們說一個數字 x 是好的當且僅當 \(\forall \ d | x\) ,有 \(d \in A\)

現在,fc 想知道有多少個不同的正整數是好的,請你告訴他吧。

d∣x : 表示 d 為 x 的約數。

\(\forall \ d | x\) ,有 \(d \in A\) : x 的任何約數都至少在 A 中出現一次。

思路:最後的好數一定是A裡面的數(因為至少包含數本身)。g[x]=1表示x存在。我們正常的求f[x]的約數有幾個,h[x]是在A裡面的x的約數個數。如果f[x]==h[x]則說明都在了。這裡是調和級數的複雜度\(O(n\log{n})\)(類似於 Eratosthenes 篩的思路)。

int d[1000001] = {0}; // 儲存因數倍數,初始全為 0
for (int i = 1; i <= n; i++) // 列舉 [1, n] 的數
{
    for (int j = i; j <= n; j += i) // 列舉 i 的倍數
    {
        d[j]++;
    }
}

程式碼:

// AC one more times
// nndbk
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e6 + 10;

ll a[N],f[N],g[N],h[N];

int main()
{
    ios::sync_with_stdio(false);   cin.tie(nullptr), cout.tie(nullptr);
  
    int n; cin>>n;
    ll mx = 0;
    for(int i = 1;i <= n; i++)
    {
        cin>>a[i];
        mx = max(mx,a[i]);
        g[a[i]] = 1;
    }


    for(int i = 1;i <= mx; i++)
    {
        for(int j = i;j <= mx; j += i){
            f[j]++;
            h[j] += g[i];
        }
    }
    ll ans = 0;
    for(int i = 1;i <= mx; i++)
        ans += (f[i] == h[i]);

    cout<<ans<<"\n";
    return 0;
}