zoukankan      html  css  js  c++  java
  • ARC120 题解A-E及总结

    ARC120 题解A-E及总结

    A.Max Add

    题意

    对于序列((a_1,a_2...a_n))

    操作1,2,3...k 将当前序列的最大值加入(a_i),定义(f(i))为第(i)次操作后的序列和

    求每个(f(i))

    分析

    注意到每次加入一个数以后这个数就会成为最大值,于是每次更新即可

    代码

    花了13分钟AC,感觉手速和推导速度都偏慢一点

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define eps 1e-9
    #define db long double
    #define equals(a,b) fabs(a-b) < eps
    using namespace std;
    
    typedef long long ll;
    
    
    
    inline ll rd(){
    	ll x;
    	scanf("%lld",&x);
    	return x;
    }
    
    int main(){
    	int n = rd();
    	vector<ll> mx(n + 1),v(n + 1),sum(n + 1);
    	vector<ll> ans(n + 2);
    	for(int i = 1;i <= n;i++)
    		v[i] = rd(),mx[i] = max(mx[i - 1],v[i]),sum[i] = sum[i - 1] + v[i];
    	for(int i = 1;i <= n;i++){
    		printf("%lld
    ",sum[i] + i * mx[i] + ans[i]);
    		ans[i + 1] = ans[i] + sum[i];
    	}
    }
    

    B.Uniformly Distributed

    题意

    给定(H imes W)的矩形,每个格子可能涂红、蓝、没涂。,从左上角到右下角,每次可以向右或者向下移动一格,要求路线中红蓝颜色相同。问对没涂的染色方案。

    分析

    不难意识到这是一个很强的条件,稍加分析就知道必须要对角线颜色一样。那么只需要遍历每一条对角线即可,我用的是while循环每次让x--,y++,对角线的条数应该是(H+W-1)

    代码

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define eps 1e-9
    #define db long double
    #define equals(a,b) fabs(a-b) < eps
    using namespace std;
    
    typedef long long ll;
    
    
    
    inline ll rd(){
    	ll x;
    	scanf("%lld",&x);
    	return x;
    }
    
    char s[505][505];
    const ll MOD = 998244353;
    
    inline ll ksm(ll a,ll b,ll m = MOD){
    	ll ans = 1;
    	ll base = a;
    	while(b){
    		if(b & 1) ans *= base,ans %= MOD;
    		base *= base;
    		base %= MOD;
    		b >>= 1;
    	}
    	return ans;
    }
    
    int main(){
    	int H = rd();
    	int W = rd();
    	for(int i = 1;i <= H;i++)
    		scanf("%s",s[i] + 1);
    	int t = H + W  - 1;
    	int ans = 1;
    	for(int i = 1;i <= t;i++){
    		int posx = min(i,W);
    		int posy = 1 + (i > W ? i - W : 0);
    		int cnt = 0;
    		int cnt1 = 0,cnt2 = 0;//1 == red 2 == blue
    		while(posx >= 1 && posy <= H) {
    			if(s[posy][posx] == '.') cnt++;
    			else if(s[posy][posx] == 'R') cnt1++;
    			else cnt2++;
    			posx--;
    			posy++;	
    		}
    		if(cnt1 && cnt2) {
    			ans = 0;
    			break;
    		}
    		//cerr << cnt1 << ' ' << cnt2 << '
    ';
    		if(!cnt1 && !cnt2) ans *= 2,ans %= MOD;	
    	}
    	cout << ans << '
    ';
    }
    

    C.Swaps2 转化

    题意

    给定数组(A,B) 寻找最少的操作次数让(A = B)

    每次操作选择(i,j)

    1.交换(a_i,a_{i+1})

    2.(a_i += 1)

    3.(a_{i+1} -=1)

    分析

    先找性质,把相邻两数交换相当于交换到前面的数要+1,到后面的数要-1。归结为性质就是(a_i + i)总是定值

    那么最后匹配到的位置一定有对应的(b_i + i = a'_i = a_j + j)

    即把(A)数组转化为(A_i = a_i + i),(B)中会对应到转化后的(A)

    (A:3 1 4) $B: 6 2 0 $

    转化后(A:4 3 7),(B:7 4 3)

    那么匹配位置应该是(3 1 2)

    先在要得到(1 2 3)

    不难发现其实就是此时(A)的逆序对数,那么跑一遍树状数组也就解决了

    代码

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define eps 1e-9
    #define db long double
    #define equals(a,b) fabs(a-b) < eps
    using namespace std;
    
    typedef long long ll;
    
    
    
    inline ll rd(){
    	ll x;
    	scanf("%lld",&x);
    	return x;
    }
    
    const int maxn = 2e5 + 5;
    
    struct BIT{
    	int n;
    	vector<int> v;
    	BIT(int n):n(n),v(n + 1){}
    	void add(int pos,int w){
    		for(;pos <= n;pos += pos & -pos)
    			v[pos] += w;
    	}
    	ll query(int pos){
    		ll ans = 0;
    		for(;pos;pos -= pos & -pos)
    			ans += v[pos];
    		return ans;
    	}
    };
    
     
    
    int main(){
    	int n = rd();
    	vector<int> a(n),b(n),c(n);
    	map<ll,queue<int>> mp;
    	ll tot = 0;
    	for(int i = 0;i < n;i++)
    		a[i] = rd(),a[i] = i + a[i],mp[a[i]].push(i),tot += a[i];
    	for(int i = 0;i < n;i++)
    		b[i] = rd(),b[i] = i + b[i],tot -= b[i];
    	if(tot) {
    		puts("-1");
    		return 0;
    	}
    	for(int i = 0;i < n;i++){
    		c[i] = mp[b[i]].front();
    		mp[b[i]].pop();
    		cerr << c[i] << '
    ';
    	}
    	BIT bit(n);
    	ll ans = 0;
    	for(int i = 0;i < n;i++)
    		ans += c[i]  - bit.query(c[i] + 1),bit.add(c[i] + 1,1),cerr << ans << '
    ';
    	cout << ans << '
    ';
    }
    

    D.Bracket Score 2 巧妙贪心

    题意

    给定长度(2n)权值数组(A),求一个括号匹配,使得匹配的括号对贡献和最大,一对括号的贡献计为(|a_i-a_j|)

    分析

    对数组排序,我们希望总是左边的(n)个数和右边的(n)个数匹配,这样总是可以拉大差值。而稍加思考发现这样总是可以构造的,只需标记前半数组,对该序列做括号匹配即可。

    代码

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define eps 1e-9
    #define db long double
    #define equals(a,b) fabs(a-b) < eps
    using namespace std;
    
    typedef long long ll;
    
    
    const int MOD = 1004535809;
    
    inline int rd(){
    	int x = 0;
    	char ch = getchar();
    	while(ch < '0' || ch > '9'){
    		ch = getchar();
    	}
    	while(ch >= '0' && ch <= '9'){
    		x = (ll)x * 10 % MOD + ch - '0';
    		if(x >= MOD ) x -= MOD;
    		ch = getchar();
    	}
    	return x;
    }
    
    int main(){
    	int n = rd();
    	vector<pii>v(2 * n);
    	vector<int>ans(2 * n);
    	for(int i = 0;i < 2 * n;i++)
    		v[i].fi = rd(),v[i].se = i;
    	sort(v.begin(),v.end());	
    	vector<int> pos(2 * n);
    	for(int i = 0;i < n;i++)
    		pos[v[i].se] = 1;
    	int cnt = 0;
    	int now = 0;
    	for(int i = 0;i < 2 * n;i++){
    		if(!cnt) now = pos[i],cnt = 1;
    		else if(pos[i] == now) cnt++;
    		else ans[i] = 1,cnt--;
    	}
    	for(int i = 0;i < 2 * n;i++)
    		if(ans[i]) putchar(')');
    		else putchar('(');
    }
    

    E.1D Party 神仙DP + 贪心

    题意

    (n)个点表示(n)个人的位置,要求每个人和相邻两人相遇,每次每个人可以选择向左或者向右,每秒移动一个距离

    问最短时间

    分析

    容易想到每个人一定先选择一个方向,碰都每个人以后一直往另一个方向。且连续三个人的初始方向不会相同,(其中两人不相同一定不会更差)

    那么(dp_i)表示前(i)个人走完的最短时间的两倍那么转移时枚举第(i-2)个人的初始方向

    画画图有

    [dp_i = min(max(dp_{i-2},a_i - a_{i-3}),max(dp_{i-3},a_i-a_{i-4})) ]

    代码

    注意初始化边界

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define eps 1e-9
    #define db long double
    #define equals(a,b) fabs(a-b) < eps
    using namespace std;
    
    typedef long long ll;
    
    
    const int MOD = 1004535809;
    
    inline int rd(){
    	int x = 0;
    	char ch = getchar();
    	while(ch < '0' || ch > '9'){
    		ch = getchar();
    	}
    	while(ch >= '0' && ch <= '9'){
    		x = x * 10 + ch - '0';
    		ch = getchar();
    	}
    	return x;
    }
    
    int main(){
    	int n = rd();
    	vector<int> dp(n + 2);
    	vector<int> v(n + 2);
    	for(int i = 1;i <= n;i++)
    		v[i] = rd();
    	dp[1] = 0,dp[2] = v[2] - v[1],v[n + 1] = v[n],v[0] = v[1];
    	for(int i = 3;i <= n + 1;i++)
    		dp[i] = min(max(dp[i - 2],v[i] - v[i - 3]),max(dp[i - 3],v[i] - v[i - 4]));
    	cout << dp[n + 1] / 2;
    }
    
  • 相关阅读:
    redisLock redis分布式锁
    Mabitis中的#与$符号区别及用法介绍
    pring Scheduler定时器原理分析
    SpringBoot几种定时任务
    线程池的理解
    JVM的方法区和永久带是什么关系
    JVM老年代和新生代的比例
    IO 与 NIO
    对mysql乐观锁、悲观锁、共享锁、排它锁、行锁、表锁概念的理解
    TCP滑动窗口控制流量的原理
  • 原文地址:https://www.cnblogs.com/hznumqf/p/15013061.html
Copyright © 2011-2022 走看看