zoukankan      html  css  js  c++  java
  • Codeforces Round #672 Div. 2

    线段树是假的,逆元是假的,我也是假的,啥都是假的————补题有感

    A. Cubes Sorting

    给一串数组,如果能在 n(n+1)/2-1 次交换相邻两个数使其变为升序输出YES,反之输出NO

    只有完全降序的数组需要 n(n+1)/2 次交换,判断即可

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <string>
    #include <vector>
    #define lc(i) (2*i+1)
    using namespace std;
    typedef long long ll;
    const ll mod = 1e6 + 1e6 + 5;
    ll INF = 1e18;
    int dataa[mod] = {};
    int tempa[mod] = {};
    ll ans = 1;
    int min(int b, int a) { if (a > b)return b; return a; }
    string k1,k2;
    void solve() {
    	ll m;
    	int flag = 0;
    	cin >> m;
    	for (int i = 0; i < m; i++)scanf("%d", &dataa[i]);
    	for (int i = 0; i < m - 1; i++) { if (dataa[i] <= dataa[i + 1])flag = 1; }
    	if (!flag)cout << "NO
    ";
    	else cout << "YES
    ";
    }
    int main(){
    	ll n;
    	cin >> n;
    	while (n--)
    	{
    		solve();
    	}
    }
    

    B. Rock and Lever

    给定一串数组,找出里面有多少对数字x,y有

    [x&y geqslant x igoplus y ]

    我们可以知道,当且仅当x和y二进制最高位的1所在位数相同,等式成立。先排序,然后遍历即可。

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <string>
    #include <vector>
    #define lc(i) (2*i+1)
    using namespace std;
    typedef long long ll;
    const ll mod = 1e5 + 1e5 + 5;
    ll INF = 1e18;
    ll dataa[mod] = {};
    ll cnts[1000] = {};
    int min(int b, int a) { if (a > b)return b; return a; }
    string k1,k2;
    void solve() {
    	ll m;
    	ll ans = 0;
    	cin >> m;
    	for (int i = 0; i < m; i++)scanf("%d", &dataa[i]);
    	memset(cnts, 0, sizeof(cnts));
    	sort(dataa, dataa + m);
    	int cnt = 0;
    	ll max = 1;									//max储存当前位最大的数+1
    	for (int i = 0; i < m; i++) {
    		while (dataa[i] >=max)max *= 2,cnt++;		//cnts[cnt]储存的是最高位为cnt位的数的个数
    		cnts[cnt]++;
    	}
    	for (int i = 0; i <= cnt; i++)ans += ((ll)(cnts[i]) * (ll)((cnts[i] - 1)) / (ll)(2)); //求组合
    	cout << ans << "
    ";
    }
    int main(){
    	ll n;
    	cin >> n;
    	while (n--)
    	{
    		solve();
    	}
    }
    

    C1. Pokémon Army (easy version)

    给定一串数组,取子串b1 ,b2。。。,令b1-b2+b3。。。最大,输出最大值

    没什么好说的,DP

    有以下转移方程,令F0(i)为i之前一共选了偶数数个的最大值,F1(i)为i之前一共选了奇数个的最大值,则:

    [egin{cases} F0_i=max(F1_{i-1}+a_i,F0_{i-1})\ F1_i=max(F0_{i-1}-a_i,F1_{i-1}) end{cases} ]

    简单版我们可以直接两个变量分别储存F0i和F1i之后实时更新即可

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <string>
    #include <vector>
    #include <utility>
    #include<queue>
    #define lc(i) (2*i+1)
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> P;
    const ll mod = 1e5 + 1e5 + 1e5+10;
    ll dataa[mod];
    string k1,k2;
    void solve() {
    	ll a,b;
    	ll ans = 0;
    	cin >> a >> b;
    	for (int i = 1; i <= a; i++)scanf("%lld", &dataa[i]);
    	ll max1 = dataa[1], max2 = 0;
    	for (int i = 2; i <= a; i++) {
    		ll tmp = dataa[i];
    		if (max2)tmp = max(tmp, max2 + tmp);
    		max2 = max(max2, max1 - dataa[i]);
    		max1 = max(max1, tmp);
    	}
    	cout <<max1 << '
    ';
    }
    int main(){
    	ll n;
    	cin >> n;
    	while (n--)
    	{
    		solve();
    	}
    }
    

    C2. Pokémon Army (hard version)

    比c1多了个交换数组中的两个值,然后求新数组新解的过程

    问了下大佬,大佬教了我个动态dp(,然而我线段树写的太假了,研究了一天

    首先我们知道矩阵乘法

    [egin{bmatrix} x&y end{bmatrix} imes egin{bmatrix} a & b \ c & d end{bmatrix} = egin{bmatrix} x imes a+y imes c&x imes b+y imes d end{bmatrix} ]

    只要运算支持分配律, 我们就能定义广义矩阵乘法,且新矩阵支持结合律

    即用max替代+,+替代×

    所以定义广义矩阵乘法

    [egin{bmatrix} x&y end{bmatrix} imes egin{bmatrix} a & b \ c & d end{bmatrix} = egin{bmatrix} max(x+a,y+c)&max(x+b,y+d) end{bmatrix}\ 单位矩阵为 egin{bmatrix} 0 & -INF \ -INF & 0 end{bmatrix} ]

    由上面的dp递推式,可以得出

    [egin{bmatrix} F0_{i-1}&F1_{i-1} end{bmatrix} imes egin{bmatrix} 0 & -a_i \ a_i &0 end{bmatrix} = egin{bmatrix} max(F0_{i-1},F1_{i-1}+a_i)&max(F1_{i-1},F0_{i-1}-a_i) end{bmatrix}= egin{bmatrix} F0_i & F1_i \ end{bmatrix} ]

    因此

    [egin{bmatrix} F0_n & F1_n end{bmatrix}= egin{bmatrix} F0_0 & F1_0 end{bmatrix} prod_{i=0}^{n-1}egin{bmatrix} 0 & -a_i \ a_i &0 end{bmatrix} ]

    用线段树维护一下矩阵的乘积即可。

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <string>
    #include <vector>
    #include <utility>
    #include<queue>
    #define lc(i) (2*i+1)
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> P;
    const ll mod = 1e5 + 1e5 + 1e5 + 10;
    ll dataa[mod];
    ll a, b, max_n;
    const int INF = 0x3f3f3f3f3f3f;
    struct mtx
    {
    	ll m1 = 0, m2 = -1 * INF, m3 = -1 * INF, m4 = 0;
    };
    ll n;
    vector<mtx> mtx1;
    mtx mul(mtx a, mtx b) {
    	mtx tmp;
    	tmp.m1 = max(a.m1 + b.m1, a.m2 + b.m3);
    	tmp.m2 = max(a.m1 + b.m2, a.m2 + b.m4);
    	tmp.m3 = max(a.m3 + b.m1, a.m4 + b.m3);
    	tmp.m4 = max(a.m3 + b.m2, a.m4 + b.m4);
    	return tmp;
    }
    void pushup(int k) {
    	mtx1[k] = mul(mtx1[k << 1], mtx1[k << 1 | 1]);
    }
    void build(int k, int l, int r) {
    	int a = dataa[l];
    	if (l == r)mtx1[k].m1 = 0, mtx1[k].m2 = -1 * a, mtx1[k].m3 = a, mtx1[k].m4 = 0;
    
    	else {
    		int mid = l + (r - l) / 2;
    		build(k << 1, l, mid);
    		build(k << 1 | 1, mid + 1, r);
    		pushup(k);
    	}
    }
    void updata(int p, int v, int l, int r, int k) {
    	if (l == r) {
    		mtx1[k].m1 = 0, mtx1[k].m2 = -1 * v, mtx1[k].m3 = v, mtx1[k].m4 = 0;
    	}
    	else {
    		int m = l + (r - l) / 2;
    		if (p <= m)updata(p, v, l, m, k << 1);
    		else updata(p, v, m + 1, r, k << 1 | 1);
    		pushup(k);
    	}
    }
    int main() {
    	ll m;
    	cin >> m;
    	while (m--)
    	{
    		cin >> a >> b;
    		n = a;
    		mtx1 = vector<mtx>(a << 2);
    		for (int i = 1; i <=a; i++) {
    			scanf("%lld", &dataa[i]);
    		}
    		build(1, 1, n);
    		printf("%lld
    ", max(mtx1[1].m3, mtx1[1].m4));
    		for (int i = 0; i < b; i++) {
    			int l, r;
    			cin >> l >> r;
    			swap(dataa[l], dataa[r]);
    			updata(l, dataa[l], 1, n, 1);
    			updata(r, dataa[r], 1, n, 1);
    			printf("%lld
    ", max(mtx1[1].m3, mtx1[1].m4));
    		}
    		
    
    	}
    }
    

    D. Rescue Nibel!

    给定一些灯的开关时间,问要使同一时间有k盏灯开着,有多少种操作方法

    先按灯打开时间排序,用小根堆优先队列维护该灯之前所有灯的结束时间。把所有小于当前灯打开时间的数pop掉,剩下数的个数就是能覆盖到当前灯的个数。然后ans加上覆盖个数对k-1求组合数,最后再把当前灯的结束时间加入堆中即可。

    开始写了才发现我不会算逆元( tcl

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <vector>
    #include <utility>
    #include<map>
    #include<queue>
    #include<sstream>
    #define lc(i) (2*i+1)
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> P;
    const ll mod = 998244353 ;
    ll n=0,k=0;
    P dataa[300000+15];
    int cnt[1000];
    ll f[300000 + 15];
    ll inv[300000 + 15];
    map<string, int> mp;
    string all;
    priority_queue<ll, vector<ll>, greater<long long> >  que;
    ll qpow(ll a, ll b) {
    	ll res = 1;
    	a %= mod;
    	while (b)
    	{
    		if (b & 1)
    			res = (res * a) % mod;
    		b >>= 1;
    		a = a * a % mod;
    	}
    	return res;
    }
    void pre(ll len) {
    	f[0] = 1;
    	for (int i = 1; i <= len; i++)
    		f[i] = i * f[i - 1] % mod;
    	inv[len] = qpow(f[len], mod - 2);//费马小定理
    	for (int i = len - 1; i >= 0; i--)inv[i] = inv[i + 1] * (i + 1) % mod;
    }
    ll c(ll n, ll m) {
    	if (n < m || n < 0)return 0;
    	return f[n] * inv[m] % mod * inv[n - m]%mod;
    }
    int main(){
    	cin >> n>>k;
    	//while (n--)
    	ll ans = 0;
    	for(int i=0;i<n;i++)
    	{
    		ll x, y;
    		scanf("%lld %lld", &x, &y);
    		dataa[i] = P(x, y);
    	}
    	sort(dataa, dataa + n);
    	pre(n + 1);
    	for (int i = 0; i < n; i++) {
    		while (!que.empty() && que.top() < dataa[i].first)que.pop ();
    		ans = (ans + c(que.size(), k - 1) % mod) % mod;
    		que.push(dataa[i].second);
    	}
    	cout << ans;
    }
    
    K-ON!!
  • 相关阅读:
    23种设计模式-原型模式
    23种设计模式-工厂方法模式
    23种设计模式-代理模式
    23种设计模式-装饰模式
    23种设计模式-策略模式
    CSS高度塌陷问题与解决办法
    Java: 多态
    Java: 接口
    Java: 继承
    Java: 单例设计模式
  • 原文地址:https://www.cnblogs.com/pophirasawa/p/13741959.html
Copyright © 2011-2022 走看看