zoukankan      html  css  js  c++  java
  • 2021牛客多校第二场

    来源

    G - League of Legends(dp+双端队列优化)

    类似斜率dp的思想吧,用一个双端队列维护。

    首先预处理,如果存在一个大区间包含了一个小区间,可以把大区间拿出来。因为这个大区间要么单独成为一个组,要么加入小区间所在的组,对最优解没有影响。预处理完后剩下的就是互不包含的若干区间。这一步可以使用排序+单调栈解决。

    对剩下区间排序,容易知道最优解就是连续地划分这些区间,很快就可以想到一种dp的算法。得益于预处理,剩下的区间不再互相包含,因此(i)(j)的区间的交集就可以简单地表示为(b[i]-a[j])。设dp[k][i]代表前i个区间划分为k组的最大值,可得dp方程为

    [dp[k][i]=max(dp[k-1][j]+b[j+1]-a[i]) ]

    移动项得到(省略第一维)

    [dp[i]+a[i]=dp[j]+b[j+1] ]

    这样可以用双端队列维护(dp[j]+b[j+1])的合法的最大值,每次先从头部弹出不合法的值,然后从尾部插入新的(i),保持队列内部递减。

    #include <bits/stdc++.h>
    
    #define endl '
    '
    #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 = 5e3 + 10;
    
    int q[N];
    int s, e;
    typedef pair<int, int> PII;
    ll dp[N][N];
    bool ok[N][N];
    vector<PII> seg1;
    vector<ll> seg2;
    vector<PII> tmp;
    
    bool cmp(int a, int b) {
        return a > b;
    }
    
    int main() {
        IOS;
        int n, k;
        cin >> n >> k;
        for(int i = 1; i <= n; i++) {
            int l, r;
            cin >> l >> r;
            tmp.push_back({l, r});
        }
        sort(tmp.begin(), tmp.end());
        seg1.push_back({0, 0});
        seg2.push_back(0);
        
        stack<int> st;
        for(int i = 0; i < tmp.size(); i++) { // 预处理
            while(!st.empty() && tmp[st.top()].second >= tmp[i].second) {
                seg2.push_back(tmp[st.top()].second - tmp[st.top()].first);
                st.pop();
            }
            st.push(i);
        }
        while(!st.empty()) {
            seg1.push_back(tmp[st.top()]);
            st.pop();
        }
        reverse(seg1.begin() + 1, seg1.end());
        n = seg1.size() - 1;
        for(int i = 1; i <= n; i++) {
            if(seg1[1].second - seg1[i].first > 0) {
                ok[1][i] = true;
                dp[1][i] = seg1[1].second - seg1[i].first;
            } else break;
        }
        for(int i = 2; i <= k; i++) {
            s = e = 0;
            q[e++] = i - 1;
            for(int j = i; j <= n; j++) {
                while(s != e && seg1[q[s] + 1].second - seg1[j].first <= 0) s++;
                if(s != e) {
                    ok[i][j] = 1;
                    int tar = q[s];
                    dp[i][j] = dp[i - 1][tar] + seg1[tar + 1].second - seg1[j].first;
                }
                if(ok[i - 1][j]) {
                    while(s != e && dp[i - 1][q[e - 1]] + seg1[q[e - 1] + 1].second <= dp[i - 1][j] + seg1[j + 1].second) e--;
                    q[e++] = j;
                }
            }
        }
        sort(seg2.begin() + 1, seg2.end(), cmp);
        for(int i = 1; i < seg2.size(); i++) {
            seg2[i] += seg2[i - 1];
        }
        ll ans = 0;
        for(int i = 1; i <= k; i++) {
            if(ok[i][n] && seg2.size() + i - 1 >= k) {
                ans = max(ans, dp[i][n] + seg2[k - i]);
                // cout << dp[i][n] << " " << k - i << " " << seg2[k - i] << endl;
            }
        }
        cout << ans << endl;
    }
    

    I - Penguins (模拟题)

    直接bfs,时间复杂度O(20^4)

    #include <bits/stdc++.h>
    
    #define endl '
    '
    #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)} ]

    注意上面的式子求出来的是幂,要使用欧拉降幂,最后直接对每个质数快速幂再累乘起来即可。使用__int128避免使用快速乘。

    注意欧拉降幂的条件,由于给定的模数不一定是素数,有可能会和底数不互质,此时要按情况额外加上一个(varphi(P))

    欧拉降幂

    (a^bequiv egin{cases} a^{b mod varphi(p)},\,&gcd(a,\,p)=1\ a^b,&gcd(a,\,p) e1,\,blt varphi(p)\ a^{b mod varphi(p)+varphi(p)},&gcd(a,\,p) e1,\,bgevarphi(p) end{cases} pmod p)

    这题比较卡常,要注意写法。

    时间复杂度:

    分解质因数暴力求(varphi(P)),预处理(sqrt{P})内的质数,复杂度为(O(sqrt{P}+Tfrac{sqrt{P}}{log P}))

    (O(frac{x}{logx}))次快速幂(即素数个数,由(pi(x)simfrac{x}{logx})得到)

    组合数(O(nk))递推

    统计答案大概是(xlog x)级别的。

    #include <bits/stdc++.h>
    
    #define endl '
    '
    #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;
    }
    
    inline 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++) {
                    ll tot = C[i - 1][j] + C[i - 1][j - 1];
                    C[i][j] = tot;
                    if(tot >= 2 * phi) {
                        C[i][j] = tot % phi + 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;
                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;
                    ans = mul(qpow(p, C[c][k], P), ans, P);
                    if(1ll * j * p >= N) break;
                }
            }
            cout << (ll)ans << endl;
        }
    }
    
    /*
    注意欧拉降幂的条件,非互质时的处理,不是单纯地模phi(p)。
    hack 数据
    1
    24 7 1038318
    2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
    答案:519160
    */
    

    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 '
    '
    #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] << " 
    "[i == n];
            } else 
                cout << -1 << endl;
        }
    }
    
  • 相关阅读:
    20145227 《Java程序设计》第8周学习总结
    20145227 《Java程序设计》第7周学习总结
    20145227《Java程序设计》第2次实验报告
    20145227《Java程序设计》第1次实验报告
    20145227 《Java程序设计》第6周学习总结
    20145227 《Java程序设计》第5周学习总结
    20145227 《Java程序设计》第4周学习总结
    20145227 《Java程序设计》第3周学习总结
    20145227 《Java程序设计》第2周学习总结
    20145227 《Java程序设计》第1周学习总结
  • 原文地址:https://www.cnblogs.com/limil/p/15035015.html
Copyright © 2011-2022 走看看