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;
        }
    }
    
  • 相关阅读:
    zoj 3627#模拟#枚举
    Codeforces 432D Prefixes and Suffixes kmp
    hdu 4778 Gems Fight! 状压dp
    CodeForces 379D 暴力 枚举
    HDU 4022 stl multiset
    手动转一下田神的2048
    【ZOJ】3785 What day is that day? ——KMP 暴力打表找规律
    poj 3254 状压dp
    C++中运算符的优先级
    内存中的数据对齐
  • 原文地址:https://www.cnblogs.com/limil/p/15035015.html
Copyright © 2011-2022 走看看