zoukankan      html  css  js  c++  java
  • Codeforces Round #672 (Div. 2) C2. Pokémon Army (hard version) D. Rescue Nibel!

    Codeforces Round #672 (Div. 2)

    C2. Pokémon Army (hard version)

    题意:给你一个a数组让你找到一个子数组b求 b[1] - b[2] + b[3] - b[4]……的最大值并且有q次询问每次询问一个l和r表示将a数组的a[l],与a[r]交换, 每次询问都让你求一次最大值。

    题解:

    如果你c1是用dp写的话, 这题就不好写了。

    可以想一下每次从a选一个子数组要求答案最大的话, 其值就是查分数组的大于的0和。

    如果知道了这个那么每次询问只要维护 4个值就行了。在更新答案。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 3e5 + 7;
    
    ll n, a[N], x[N];
    
    void solve() {
        int q;
        cin >> n >> q;
        for (int i = 0; i <= n + 1; i++) {
            x[i] = 0;
        }
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
    
        }
        a[n + 1] = 0;
        ll ans = 0;
        for (int i = 1; i <= n; i++) {
            x[i] = a[i] - a[i + 1];
            if (x[i] > 0) ans += x[i];
        }
    
        cout << ans << endl;
    
        while (q--) {
            int l, r; cin >> l >> r;
            swap(a[l], a[r]);
            if (l == r) {
                cout << ans << endl;
                continue;
            }
            if (x[l] > 0) ans -= x[l];
            if (x[r] > 0) ans -= x[r];
            if (x[l - 1] > 0) ans -= x[l - 1];
            if (x[r - 1] > 0 && r - 1 != l) ans -= x[r - 1];
    
          
            x[l - 1] = a[l - 1] - a[l];
            x[l] = a[l] - a[l + 1];
            x[r] = a[r] - a[r + 1];
            x[r - 1] = a[r - 1] - a[r];
            if (x[l] > 0) {
                ans += x[l];
            } 
            if (x[r] > 0) {
                ans += x[r];
            }
            if (l - 1 && x[l - 1] > 0) {
                ans += x[l - 1];
            }
            if (r - 1 && l != r - 1&& x[r - 1] > 0) {
                ans += x[r - 1];
            }
            cout << ans << endl;  
        }
    
    }
    
    
    
    int main() {
        ios::sync_with_stdio(0);
        int t; cin >> t;
        while (t--) {
            solve();
        }
    }
    

    D. Rescue Nibel!

    题意:

    给你n盏灯, 每盏灯都会在固定时间打开, 问选k盏灯且这k盏灯在某一个时刻一定全部打开,有多少种选择方法?

    题解:

    这题比赛的时候没有想出来。。。太菜了。

    如果枚举每个时刻有多少盏灯打开, 那在这个时刻的答案是 $$inom{k}{同时打开的灯} $$

    但是会有重复计算。

    所以我们可以每次只计算与开始打开灯贡献其它就不用在算了。

    (x[i])表示第 (i)个时刻有 (x[i]) 个灯打开。

    (vis[i]) 表示 第(i)个时刻刚打开 (vis[i])个灯。

    那么第(i) 个时刻的答案就是 (inom{k}{x[i]} - inom{k}{x[i] - vis[i]})

    这样计算就会有重复的啦。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 7e5 + 7;
    const ll mod = 998244353;
    long long fac[N]; // 阶乘表
    ll n, k;
    
    vector<ll> g;
    
    vector<pair<ll, ll> > cnt;
    
    int get_id(ll x) {
        return lower_bound(g.begin(), g.end(), x) - g.begin() + 1;
    }
    
    long long qpow(long long x, long long n) { 
    	long long res = 1; 
    	for (; n; n >>= 1, x = x * x % mod) 
    		if (n & 1) res = res * x % mod; 
    	return res; 
    }
    
    long long inv(long long a) { // 返回逆元 费马小定理
    	return qpow(a, mod-2)%mod;
    }
    
    void solves() { // 计算阶乘表
    	fac[0] = 1;
    	for(int i = 1;i < N; i++) {
    		fac[i] = (fac[i-1]*i)%mod;
    	}
    }
    
    long long comb(long long n, long long k) {
    	if(k > n) return 0;
    	return (fac[n]*inv(fac[k])%mod * inv(fac[n-k])%mod) % mod;
    }
    
    ll x[N], vis[N];
    
    void solve() {
        solves();
        cin >> n >> k;
        for (int i = 1; i <= n; i++) {
            ll l, r; cin >> l >> r;
            g.push_back(l), g.push_back(r);
            cnt.push_back({l, r});
        }
        sort(g.begin(), g.end());
        g.erase(unique(g.begin(), g.end()), g.end());
    
        for (int i = 0; i < cnt.size(); i++) {
            int l = get_id(cnt[i].first), r = get_id(cnt[i].second);
            x[l]++, x[r + 1]--;
            vis[l]++;
        }
        for (int i = 1; i <= g.size() + 10; i++) {
            x[i] += x[i - 1];
        }
        ll ans = 0;
        for (int i = 1; i <= g.size() + 10; i++) {
            if (vis[i]) {
           
                ans = (ans + comb(x[i], k)) % mod;
                ans = (ans - comb((x[i] - vis[i]), k) + mod) % mod;
            }
                
        }
        cout << ans << endl;
    
    
    
    }
    
    
    
    int main() {
        ios::sync_with_stdio(0);
        int t = 1; //cin >> t;
        while (t--) {
            solve();
        }
    }
    
  • 相关阅读:
    刷题总结——射箭(bzoj2732)
    算法复习——半平面交(bzoj2618凸多边形)
    刷题总结——spoj1812(后缀自动机+DP)
    刷题总结:最长公共字串(spoj1811)(后缀自动机)
    算法复习——后缀自动机
    算法复习——splay+启发式合并(bzoj2733-永无乡)
    北京集训TEST13——PA(Goodness)
    linux命令学习笔记(46):vmstat命令
    linux命令学习笔记(45):free 命令
    linux命令学习笔记(44):top命令
  • 原文地址:https://www.cnblogs.com/BOZHAO/p/13733213.html
Copyright © 2011-2022 走看看