Codeforces Round 521 (Div. 3)

2024-04-13 05:12
文章标签 codeforces round div 521

本文主要是介绍Codeforces Round 521 (Div. 3),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

A. Frog Jumping

B. Disturbed People

C. Good Array

D. Cutting Out

E. Thematic Contests

F1. Pictures with Kittens (easy version)

F2. Pictures with Kittens (hard version)


A. Frog Jumping

直接模拟即可注意数据范围需要开long long

void solve(){LL a,b,k;cin>>a>>b>>k;cout << (k+1)/2*a - k/2*b << endl;return ;
}

B. Disturbed People

简单贪心我们可以发现如果对于一个 1 0 1 那么我调整最后一个1 变为0 是最好的因为这样让后面也只会减少贡献所以调整后面的1即可

void solve(){cin>>n;for(int i=1;i<=n;i++) cin>>a[i];int ans = 0;for(int i=1;i<=n-2;i++){if(a[i] and !a[i+1] and a[i+2]){ans ++ ;a[i+2]=0;}}cout << ans << endl;return ;
}

C. Good Array

直接按照题目意思模拟即可,同时注意到如果删除的数恰好是后面总和的一半的时候需要特判

void solve(){map<LL,int> mp;cin>>n;LL sum =0;for(int i=1;i<=n;i++){cin>>a[i];mp[a[i]]++;sum += a[i];}vector<int> ans;for(int i=1;i<=n;i++){LL now = sum -a[i];if(now%2==0 and mp.count(now/2)){if(a[i]*2==now){if(mp[a[i]]>=2) ans.push_back(i);}else ans.push_back(i);}}cout << ans.size() << endl;for(auto&v:ans) cout << v << ' ';cout << endl; return ;
}

D. Cutting Out

首先我们可以简单的发现是具有二分性质的,然后我们就可以二分数量,check函数对一个数的个数整除即可,用map记录

bool check(int x){int cnt = 0;for(auto&[v,w]:mp) cnt += w/x;return cnt>=m;
}
void solve(){cin>>n>>m;for(int i=1;i<=n;i++){int x; cin>>x;mp[x]++;}int l=1,r=n;while(l<r){int mid=l+r+1>>1;if(check(mid)) l=mid;else r=mid-1;}vector<int> res;for(auto&[v,w]:mp){int t = w/l;while(t--) res.push_back(v);}for(int i=0;i<m;i++) cout<<res[i]<<' ';cout<<endl;return ;
}

E. Thematic Contests

注意厘清题目意思,对于每一个数我们只在乎的是它的数量,然后对于题目意思的翻倍处理可以明显的知道最多只会处理20次以内2^{20}>1e6,所以对于整个数的来取得的话我们直接看后20位即可,同时对于开头第一个数肯定是 1-smax,记录一下即可,简单判断时间复杂度是可行的

map<LL,int> mp;
int check(int x){int sum = 0;for(int i=max(1,n-20);i<=n;i++){if(a[i]>=x){sum += x;x *= 2;}}return sum;
}
void solve(){cin>>n;for(int i=1;i<=n;i++){int x; cin>>x;mp[x]++;smax=max(smax,mp[x]);}for(auto&[v,w]:mp){a[++m]=w;}sort(a+1,a+1+m);int ans = 1;for(int i=1;i<=smax;i++){ans = max(ans,check(i));}cout << ans << endl;return ;
}

F1. Pictures with Kittens (easy version)

我们可以明显的看出这是最优性问题,我们考虑dp,首先定义状态,首先第一是数量,第二维就是当前整个数选的是什么位置,同时转移来源是对于当前要选的数的前k个以内的,所以转移是ok的,同时注意求最大值,也就是一开始有些是不可以转移的,所以定义为负无穷即可

LL dp[M][M];
int w[M];void solve(){cin>>n>>k>>m;for(int i=1;i<=n;i++) cin>>w[i];for(int i=0;i<=n;i++)for(int j=0;j<=n;j++)dp[i][j]=-1e18;dp[0][0]=0;for(int i=1;i<=n;i++)for(int j=1;j<=i and j<=m;j++)for(int u=max(i-k,0);u<i;u++){dp[j][i]=max(dp[j][i],dp[j-1][u]+w[i]);}LL ans = -1;for(int i=n-k+1;i<=n;i++) ans = max(ans,dp[m][i]);cout << ans << endl;return ;
}

F2. Pictures with Kittens (hard version)

依照上一题的分析同时我们注意到数据范围也就是只能是用n^2的时间复杂度来通过本题,我们在上题的分析基础上分析,可以发现dp[i](选的第i个数的转移来源 一定是选的第i-1个数)所以考虑对此优化,当我选第i个数的时候选到第j个位置时,后面的选到第j+1的数只能由dp[i-1][(max(0,j-k),j]组成这个状态的变化可以通过在转移j的同时用单调队列优化上一层的状态,这样就是满足要求的时间复杂度

LL dp[M][M];
int w[M];void solve(){cin>>n>>k>>m;for(int i=1;i<=n;i++) cin>>w[i];if(n/k>m){cout<<-1<<endl;return ;}for(int i=0;i<=n;i++)for(int j=0;j<=n;j++)dp[i][j]=-1e18;dp[0][0]=0;for(int i=1;i<=m;i++){deque<int> q;q.push_back(0);for(int j=1;j<=n;j++){while(!q.empty() and j-q.front()>k) q.pop_front();dp[i][j]=dp[i-1][q.front()]+w[j];while(!q.empty() and dp[i-1][j]>=dp[i-1][q.back()]) q.pop_back();q.push_back(j);}	}LL ans = -1;for(int i=n-k+1;i<=n;i++) ans = max(ans,dp[m][i]);cout << ans << endl;return ;
}

常见的dp从n^3-->n^2都是依靠转移的状态是不是只有上一层,然后通过记录上一层的信息来做直接转移而优化一层循环

这篇关于Codeforces Round 521 (Div. 3)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/899221

相关文章

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

Codeforces Round #261 (Div. 2)小记

A  XX注意最后输出满足条件,我也不知道为什么写的这么长。 #define X first#define Y secondvector<pair<int , int> > a ;int can(pair<int , int> c){return -1000 <= c.X && c.X <= 1000&& -1000 <= c.Y && c.Y <= 1000 ;}int m

Codeforces Beta Round #47 C凸包 (最终写法)

题意慢慢看。 typedef long long LL ;int cmp(double x){if(fabs(x) < 1e-8) return 0 ;return x > 0 ? 1 : -1 ;}struct point{double x , y ;point(){}point(double _x , double _y):x(_x) , y(_y){}point op

Codeforces Round #113 (Div. 2) B 判断多边形是否在凸包内

题目点击打开链接 凸多边形A, 多边形B, 判断B是否严格在A内。  注意AB有重点 。  将A,B上的点合在一起求凸包,如果凸包上的点是B的某个点,则B肯定不在A内。 或者说B上的某点在凸包的边上则也说明B不严格在A里面。 这个处理有个巧妙的方法,只需在求凸包的时候, <=  改成< 也就是说凸包一条边上的所有点都重复点都记录在凸包里面了。 另外不能去重点。 int

Codeforces 482B 线段树

求是否存在这样的n个数; m次操作,每次操作就是三个数 l ,r,val          a[l] & a[l+1] &......&a[r] = val 就是区间l---r上的与的值为val 。 也就是意味着区间[L , R] 每个数要执行 | val 操作  最后判断  a[l] & a[l+1] &......&a[r] 是否= val import ja

CSS实现DIV三角形

本文内容收集来自网络 #triangle-up {width: 0;height: 0;border-left: 50px solid transparent;border-right: 50px solid transparent;border-bottom: 100px solid red;} #triangle-down {width: 0;height: 0;bor

创建一个大的DIV,里面的包含两个DIV是可以自由移动

创建一个大的DIV,里面的包含两个DIV是可以自由移动 <body>         <div style="position: relative; background:#DDF8CF;line-height: 50px"> <div style="text-align: center; width: 100%;padding-top: 0px;"><h3>定&nbsp;位&nbsp;

Codeforces Round 971 (Div. 4) (A~G1)

A、B题太简单,不做解释 C 对于 x y 两个方向,每一个方向至少需要 x / k 向上取整的步数,取最大值。 由于 x 方向先移动,假如 x 方向需要的步数多于 y 方向的步数,那么最后 y 方向的那一步就不需要了,答案减 1 代码 #include <iostream>#include <algorithm>#include <vector>#include <string>

CF#271 (Div. 2) D.(dp)

D. Flowers time limit per test 1.5 seconds memory limit per test 256 megabytes input standard input output standard output 题目链接: http://codeforces.com/contest/474/problem/D We s

CF #278 (Div. 2) B.(暴力枚举+推导公式+数学构造)

B. Candy Boxes time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output 题目链接: http://codeforces.com/contest/488/problem/B There