Codeforces Round #638 (Div. 2)
Posted kikokiko
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #638 (Div. 2)相关的知识,希望对你有一定的参考价值。
A - Phoenix and Balance
最大的那个比其他所有的和都要大
所以最大那个的配上最小的(frac{n}{2}-1)个分成一组
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
using LL = int_fast64_t;
int n;
void solve(){
cin >> n;
int ret1 = 0, ret2 = 0;
for(int i = 1; i <= n; i++) ret1 += (1<<i);
for(int i = 1; i <= n / 2 - 1; i++) ret2 += (1<<i);
ret2 += (1<<n);
cout << abs(ret1 - ret2 - ret2) << endl;
}
int main(){
____();
int T; for(cin >> T; T; T--) solve();
return 0;
}
B - Phoenix and Beauty
其实就要构造一个循环节为(k)的循环串
那么如果不同的数出现次数大于(k),就不可能构造出来
否则先取不同的数字,然后补全长度到(k)
复制(100)遍就好了
复制一百遍能保证原序列必然能作为当前序列的一个子序列出现
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 222;
int n,k,A[MAXN];
void solve(){
cin >> n >> k;
vector<int> vec;
for(int i = 1; i <= n; i++){
cin >> A[i];
vec.emplace_back(A[i]);
}
sort(vec.begin(),vec.end());
vec.erase(unique(vec.begin(),vec.end()),vec.end());
if(vec.size()>k){
cout << -1 << endl;
return;
}
while(vec.size()<k) vec.emplace_back(1);
cout << vec.size() * 100 << endl;
for(int i = 1; i <= 100; i++) for(int x : vec) cout << x << ‘ ‘;
cout << endl;
}
int main(){
____();
int T; for(cin >> T; T; T--) solve();
return 0;
}
C - Phoenix and Distribution
因为和原串顺序没关系,可以先把原串排个序,好操作
因为每个串都不能是空的,所以首先贪心地把前(k)个字符赋给(k)个字符串
1.这个时候如果这(k)个字符不完全一样,那么可以直接输出最大的那个,因为其他字符可以接在最小的那个后面,字典序必然是第一个字符最大的那个大
2.现在考虑前(k)个字符相同的情况
-
那么如果剩下的(n-k)个字符完全相同,那么就可以把剩下的(n-k)个字符分配到(k)个字符串上,然后取最长的那个就是字典序最大的
-
如果不完全相同,就可以直接把剩下的全部接在第一个字符之后然后输出
可以这样考虑,如果现在还是把这(n-k)个字符依次循环分配到(k)个字符串上,那么对于某一个串必然存在这么一个位置,这个位置的字符和
它上一个串的这个位置是不同的,那么按最开始的办法,把剩下的字符全部接在字典序小的后面,但其实这样不是最优的
如果分配完前(k)个字符之后,把剩下的(k-n)个全部接在第一个串后面必然更优,因为这样大的那个字符出现的位置会往后推
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2e5+7;
int n,k,cnt[26],m;
char s[MAXN],t[MAXN];
void solve(){
cin >> n >> k >> (s+1);
sort(s+1,s+1+n);
if(k==1){
cout << s+1 << endl;
return;
}
bool same = true;
for(int i = 2; i <= k; i++){
if(s[i]!=s[i-1]){
same = false;
break;
}
}
if(!same){
cout << s[k] << endl;
return;
}
set<char> S;
for(int i = k + 1; i <= n; i++) S.insert(s[i]);
if(S.empty()){
cout << s[1] << endl;
return;
}
if(S.size()>1){
cout << (s+k) << endl;
return;
}
cout << s[1]; for(int i = 1; i <= (n-k)/k + ((n-k)%k!=0?1:0); i++) cout << s[k+1];
cout << endl;
}
int main(){
____();
int T; for(cin >> T; T; T--) solve();
return 0;
}
D - Phoenix and Science
假设我们记当前的总质量为(w),细菌数量为(x),那么对于当前这天,我可以选择让(y)个细菌分裂,那么下一天细菌的数量就会变成(x+y),同时总质量会变成(w+x+y),而(0le y le x),所以细菌数量最多增加一倍
考虑如何能够最快到达(n),因为细菌数量(x)是不会减少的,所以我们必须保证当前这天的总质量(w)和需要到达的总质量(n)的差值(delta)小于等于(x),这样就可以限定我们这一天最多能分裂多少细菌,使得下一天的(delta)小于下一天的细菌数量(x),这给我们提供了一个上限,所以为了能尽快到达(n),最优的办法就是分裂选取这个最大值,同时不能超过当前的细菌数量,贪心分裂就好了
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
int n;
void solve(){
cin >> n;
int tot = 1, add = 1;
vector<int> vec;
while(tot<=n){
int delta = n - tot;
if(add*2>=delta){
vec.push_back(delta-add);
break;
}
vec.push_back(min(delta/2-add,add));
add += vec.back();
tot += add;
}
cout << vec.size() << endl;
for(int x : vec) cout << x << ‘ ‘; cout << endl;
}
int main(){
____();
int T; for(cin >> T; T; T--) solve();
return 0;
}
E - Phoenix and Berries
最简单的情况就是每个框子只装同种颜色的,这时候最多装(lfloor frac{sum A}{k}
floor + lfloor frac{sum B}{k}
floor)个
现在来考虑装同一棵树的,可以发现不同的情况只和同棵树这类放置方案选取的第一种颜色(或者第二种颜色)总数对(k)的模数有关
所以可以背包搞出来
这时候取模掉的那些可以直接按同颜色的装
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 555;
using LL = int_fast64_t;
LL n,k,A[MAXN],B[MAXN];
bool f[2][MAXN];
int main(){
____();
cin >> n >> k;
LL tota = 0, totb = 0;
for(int i = 1; i <= n; i++) cin >> A[i] >> B[i], tota += A[i], totb += B[i];
LL ret = tota/k + totb/k;
int tg = 0; f[tg][0] = true;
for(int i = 1; i <= n; i++){
tg ^= 1;
memcpy(f[tg],f[tg^1],sizeof(f[tg]));
for(int pre = 0; pre < k; pre++){
if(!f[tg^1][pre]) continue;
for(int cur = 1; cur <= min(A[i],k); cur++){
if(k-cur>B[i]) continue;
f[tg][(pre+cur)%k] = true;
}
}
}
for(int i = 1; i < k; i++) if(f[tg][i]) ret = max(ret,(tota-i)/k+(totb-(k-i))/k+1);
cout << ret << endl;
return 0;
}
F - Phoenix and Memory
因为保证合法,所以找到一个解十分简单,建一个优先队列,枚举(i)从(1)到(n),如果有以当前点为左端点的区间,就把这些区间放到优先队列里去,每次选择右端点最靠左的那个放到当前位置,这样贪心做肯定可以得到一组解
现在考虑怎么判断解唯一
如果解不唯一,那么必然存在两个位置的点可以互换,现在就要找出一对这样可以交换的点就好了
对于之前的一段可选区间([L_i,R_i])如果把他放在位置(x)上,现在的一段可选区间([L_j,R_j]),放在位置(y)上,如果满足:(egin{cases} L_jle xle R_j \ L_ile yle R_i end{cases})
那就说明这两个位置是可以交换的,这个可以用线段树做,每次确定一个区间的位置了之后,就把这个区间的右端点,赋给这个点,然后我们对于当前放置在(i)点的区间([L_i,R_i]),我们找([L_i,i))之间的最大值,如果大于等于(i),就必然存在可以交换的点了,暴力找出这个点就好了
找到之后对于后面的位置,唯一去确定就好了,因为已经找到两个不同序列了
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 2e5+7;
const int INF = 0x3f3f3f3f;
int n,dz[MAXN];
vector<pair<int,pair<int,int>>> vec[MAXN];
int rmax[MAXN];
template<typename T>
struct SegmentTree{
T maxx[MAXN<<2],lazy[MAXN<<2];
int l[MAXN<<2],r[MAXN<<2];
#define ls(rt) rt << 1
#define rs(rt) rt << 1 | 1
#define pushup(rt) maxx[rt] = max(maxx[ls(rt)],maxx[rs(rt)])
void build(int L, int R, int rt){
l[rt] = L; r[rt] = R;
lazy[rt] = 0;
if(L+1==R) return;
int mid = (L + R) >> 1;
build(L,mid,ls(rt)); build(mid,R,rs(rt));
}
void pushdown(int rt){
if(!lazy[rt]) return;
lazy[ls(rt)] += lazy[rt]; lazy[rs(rt)] += lazy[rt];
maxx[ls(rt)] += lazy[rt]; maxx[rs(rt)] += lazy[rt];
lazy[rt] = 0;
}
void update(int L, int R, int rt, T x){
if(L>=r[rt] || l[rt]>=R) return;
if(L<=l[rt] && r[rt]<=R){
lazy[rt] += x; maxx[rt] += x;
return;
}
pushdown(rt);
update(L,R,ls(rt),x); update(L,R,rs(rt),x);
pushup(rt);
}
T query(int L, int R, int rt){
if(L>=r[rt] || l[rt]>=R) return -INF;
if(L<=l[rt] && r[rt]<=R) return maxx[rt];
pushdown(rt);
return max(query(L,R,ls(rt)),query(L,R,rs(rt)));
}
};
SegmentTree<int> ST;
int main(){
____();
cin >> n;
for(int i = 0; i < n; i++){
int l, r; cin >> l >> r;
l--, r--;
rmax[i] = r;
vec[l].push_back(make_pair(r,make_pair(l,i)));
}
priority_queue<pair<int,pair<int,int>>,vector<pair<int,pair<int,int>>>,greater<pair<int,pair<int,int>>>> que;
ST.build(0,n,1);
bool unq = true;
vector<int> ret1,ret2;
for(int i = 0; i < n; i++){
for(auto seg : vec[i]) que.push(seg);
auto p = que.top();
que.pop();
ret1.push_back(p.second.second);
if(!unq){
ret2.push_back(p.second.second);
continue;
}
ST.update(i,i+1,1,p.first);
if(!i) continue;
int maxx = ST.query(p.second.first,i,1);
if(maxx<i) continue;
unq = false;
int pos = 0;
for(int j = p.second.first; j < i; j++){
if(rmax[ret1[j]]>=i){
pos = j;
break;
}
}
copy(ret1.begin(),ret1.end(),back_inserter(ret2));
swap(ret2[pos],ret2[i]);
}
if(unq){
cout << "YES" << endl;
for(int i = 0; i < n; i++) dz[ret1[i]] = i+1;
for(int i = 0; i < n; i++) cout << dz[i] << ‘ ‘; cout << endl;
}
else{
cout << "NO" << endl;
for(int i = 0; i < n; i++) dz[ret1[i]] = i+1;
for(int i = 0; i < n; i++) cout << dz[i] << ‘ ‘; cout << endl;
for(int i = 0; i < n; i++) dz[ret2[i]] = i+1;
for(int i = 0; i < n; i++) cout << dz[i] << ‘ ‘; cout << endl;
}
return 0;
}
以上是关于Codeforces Round #638 (Div. 2)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #638 (Div. 2)
Codeforces Round #638 (Div. 2)
Codeforces Round #638 (Div. 2)
Codeforces Round #638 (Div. 2)(A~B)
Codeforces Round #638 (Div. 2) A~C题解
CF A. Phoenix and Balance Codeforces Round #638 (Div. 2) 5月1号