1. 程式人生 > 其它 >2021牛客多校第二場

2021牛客多校第二場

來源

I - Penguins (模擬題)

直接bfs,時間複雜度O(20^4)

#include <bits/stdc++.h>

#define endl '\n'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mp make_pair
#define seteps(N) fixed << setprecision(N) 
typedef long long ll;

using namespace std;
/*-----------------------------------------------------------------*/

ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f

const int N = 25;
const double eps = 1e-5;

bool vis[N][N][N][N];
char a[N][N], b[N][N];
int fx[4][2] = {
    {1, 0},
    {-1, 0},
    {0, 1},
    {0, -1}
};

int fxidl[4] = {2, 1, 0, 3};
int fxidr[4] = {2, 0, 1, 3};

bool check(int x,int y) {
    if(x <= 0 || x > 20 || y <= 0 || y > 20) return false;
    return true;
}

struct node {
    int x1, y1, x2, y2;
};

node up[N][N][N][N];
int rfx[N][N][N][N];

char cfx[] = "DLRU";

bool bfs(int x1, int y1, int x2, int y2) {
    queue<node> q;
    q.push({x1, y1, x2, y2});
    vis[x1][y1][x2][y2] = 1;
    while(!q.empty()) {
        node cur = q.front();
        q.pop();
        x1 = cur.x1, y1 = cur.y1, x2 = cur.x2, y2 = cur.y2;
        if(x1 == 20 && y1 == 1 && x2 == 1 && y2 == 1) {
            return true;
        }
        for(int i = 0; i < 4; i++) {
            int f1 = fxidl[i], f2 = fxidr[i];
            int nx1 = x1 + fx[f1][0], ny1 = y1 + fx[f1][1];
            int nx2 = x2 + fx[f2][0], ny2 = y2 + fx[f2][1];
            if(!check(nx1, ny1) || a[ny1][nx1] == '#') {nx1 = x1, ny1 = y1;}
            if(!check(nx2, ny2) || b[ny2][nx2] == '#') {nx2 = x2, ny2 = y2;}
            if(vis[nx1][ny1][nx2][ny2]) continue;
            vis[nx1][ny1][nx2][ny2] = 1;
            q.push({nx1, ny1, nx2, ny2});
            up[nx1][ny1][nx2][ny2] = cur;
            rfx[nx1][ny1][nx2][ny2] = i;
        }
    }
    return false;
}

int main() {
    IOS;
    for(int i = 1; i <= 20; i++) {
        for(int j = 1; j <= 20; j++) {
            cin >> a[i][j];
        }
        for(int j = 1; j <= 20; j++) {
            cin >> b[i][j];
        }
    }
    up[20][20][1][20] = {0, 0, 0, 0};
    
    bfs(20, 20, 1, 20);
    vector<int> ans;
    int x1 = 20, y1 = 1, x2 = 1, y2 = 1;
    while(x1) {
        ans.push_back(rfx[x1][y1][x2][y2]);
        node u = up[x1][y1][x2][y2];
        x1 = u.x1, y1 = u.y1, x2 = u.x2, y2 = u.y2;
    }
    ans.pop_back();
    reverse(ans.begin(), ans.end());
    cout << ans.size() << endl;
    for(int i = 0; i < ans.size(); i++) cout << cfx[ans[i]];
    cout << endl;
    x1 = 20, y1 = 20, x2 = 1, y2 = 20;
    a[y1][x1] = 'A';
    b[y2][x2] = 'A';
    for(int i = 0; i < ans.size(); i++) {
        int f1 = fxidl[ans[i]], f2 = fxidr[ans[i]];
        int nx1 = x1 + fx[f1][0], ny1 = y1 + fx[f1][1];
        int nx2 = x2 + fx[f2][0], ny2 = y2 + fx[f2][1];
        if(!check(nx1, ny1) || a[ny1][nx1] == '#') {nx1 = x1, ny1 = y1;}
        if(!check(nx2, ny2) || b[ny2][nx2] == '#') {nx2 = x2, ny2 = y2;}
        a[ny1][nx1] = 'A';
        b[ny2][nx2] = 'A';
        x1 = nx1, y1 = ny1, x2 = nx2, y2 = ny2;
    }    
    for(int i = 1; i <= 20; i++) {
        for(int j = 1; j <= 20; j++) cout << a[i][j];
        cout << " ";
        for(int j = 1; j <= 20; j++) cout << b[i][j];
        cout << endl;
    }
}


J - Product of GCDs(數學)

分別算每個質因子\(p^c\)的貢獻。設\(f_{p,c}\)代表陣列中至少包含\(p^c\)的數的個數,則取\(k\)個數的方案數就是\(C(f_{p,c},k)\)。從而可得取k個數的gcd恰好包含\(p^c\)的方案數數為\(C(f_{p,c},k)-C(f_{p,c+1},k)\)。故質因子\(p\)的貢獻的冪為

\[(C(f_{p,1},k)-C(f_{p,2},k))+2(C(f_{p,2},k)-C(f_{p,3},k))+...+c(C(f_{p,c},k)-C(f_{p,c+1},k))=\sum{C(f_{p,c},k)} \]

注意上面的式子求出來的是冪,要模\(\varphi(P)\)

,最後直接對每個質數快速冪再累乘起來即可。使用__int128避免使用快速乘。

這題比較卡常,要注意寫法。

時間複雜度:

分解質因數暴力求\(\varphi(P)\),預處理\(\sqrt{P}\)內的質數,複雜度為\(O(\sqrt{P}+T\frac{\sqrt{P}}{log P})\)

\(O(\frac{x}{logx})\)次快速冪(即素數個數,由\(\pi(x)\sim\frac{x}{logx}\)得到)

組合數\(O(nk)\)遞推

統計答案大概是\(x\log x\)級別的。

#include <bits/stdc++.h>

#define endl '\n'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mp make_pair
#define seteps(N) fixed << setprecision(N) 
typedef long long ll;

using namespace std;
/*-----------------------------------------------------------------*/

ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f

const int N = 8e4 + 10;
const int M = 1e7 + 10;
const double eps = 1e-5;

int pri[M], cnt;
bool isnp[M];
int num[N];
ll C[40001][31];

ll getphi(ll n) {
    ll p = n;
    for(int i = 0; 1ll * pri[i] * pri[i] < p; i++) {
        if(n % pri[i] == 0) {
            p = p / pri[i] * (pri[i] - 1);
            while(n % pri[i] == 0) n /= pri[i];
        } 
    }
    if(n > 1) p = p / n * (n - 1);
    return p;
}

ll mul(ll x, ll y, ll m) {
    return (__int128)x * y % m; 
}

inline ll qpow(ll a, ll b, ll m) {
    ll res = 1;
    while(b) {
        if(b & 1) res = mul(res, a, m);
        a = mul(a, a, m);
        b = b >> 1;
    }
    return res;
}

int main() {
    IOS;
    isnp[1] = 1;
    for(int i = 2; i < M; i++) {
        if(!isnp[i]) {
            pri[cnt++] = i;          
        }
        for(int j = 0; j < cnt && 1ll * pri[j] * i < M; j++) {
            isnp[i * pri[j]] = 1;
            if(i % pri[j] == 0) break;
        }
    }
    int t;
    cin >> t;
    while(t--) {
        memset(num, 0, sizeof num);
        int n, k;
        ll P;
        cin >> n >> k >> P;
        ll phi = getphi(P);

        for(int i = 1; i <= n; i++) C[i][0] = 1;
        C[1][1] = 1;
        for(int i = 2; i <= n; i++) {
            for(int j = 1; j <= min(k, i); j++) {
                C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % phi;
            }
        }
        ll ans = 1;
        for(int i = 1; i <= n; i++) {
            int x;
            cin >> x;
            num[x]++;
        }

        for(int i = 0; i < cnt; i++) {   
            int p = pri[i];
            if(p > N) break;
            ll pow = 0;
            for(int j = p; j < N; j = j * p) {
                int c = 0;
                for(int x = j; x < N; x += j) {
                    c += num[x];
                }
                if(c < k) break; 
                pow += C[c][k];
                pow %= phi;
                if(1ll * j * p >= N) break;
            }
            
            if(pow) {
                ans = mul(qpow(p, pow, P), ans, P);
            }
        }
        cout << (ll)ans << endl;
    }
}

K - Stack (構造)

使用二元組(var,id)​,其中var從1開始遞增,代表陣列b的值;id從n開始遞減。當陣列b沒有值時,var遞增、id遞減,然後將二元組插入棧中;當陣列b的值為x時,一直彈棧到彈出的二元組var==x,此時令彈出的二元組的id修改為當前的id,將當前的id修改為x,重新插入棧中。

可以發現過程中插入的二元組始終滿足題目要求。最後將二元組以var為第一關鍵字,id為第二關鍵字排序編號,就可以得到陣列a了。

#include <bits/stdc++.h>

#define endl '\n'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mp make_pair
#define seteps(N) fixed << setprecision(N) 
typedef long long ll;

using namespace std;
/*-----------------------------------------------------------------*/

ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f

const int N = 3e6 + 10;
const double eps = 1e-5;
typedef long long ll;

typedef pair<int, int> PII;
int b[N];
vector<PII> ans;
int res[N];
int pos[N];
bool cmp(int a, int b) {
    return ans[a - 1] < ans[b - 1];
}

int main() {
    IOS;
    int t;
    // cin >> t;
    t = 1;
    while(t--) {
        ans.clear();
        stack<PII> st;
        int n, k;
        cin >> n >> k;
        for(int i = 1; i <= n; i++) b[i] = 0;
        bool ok = true;
        for(int i = 1; i <= k; i++) {
            int p, x;
            cin >> p >> x;
            b[p] = x;
            if(x <= 0) ok = false;
        }
        int id = n + 1;
        int val = 0;
        
        for(int i = 1; i <= n; i++) {
            pos[i] = i;
            if(b[i] && st.size() + 1 < b[i]) {
                ok = false;
                break;
            } else {
                id--;
                if(b[i])
                    val = b[i];
                else
                    val++;
                PII pi{val, id};
                while(!st.empty() && st.top() > pi) st.pop();
                st.push(pi);
                ans.push_back(pi);
                // cout << pi.first << " " << pi.second << endl;
            }
        }
        if(ok) {
            sort(pos + 1, pos + 1 + n, cmp);
            for(int i = 1; i <= n; i++) {
                res[pos[i]] = i;
            }
            for(int i = 1; i <= n; i++)
                cout << res[i] << " \n"[i == n];
        } else 
            cout << -1 << endl;
    }
}