Codeforces Round #638 (Div. 2) 题解 (ABCDE)

https://codeforces.com/contest/1348

A. Phoenix and Balance

想了想,还是不略了

显然有 \(2^1+2^2+...+2^{n-1}<2^n\),前 \(n-1个\) 数随你选 \(\dfrac n 2\) 个一定小于 \(2^n\)。为了两边硬币质量更靠近,在前 \(n-1\) 中要选最大的 \(\dfrac n 2\) 个硬币

求和公式搞一搞

#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
const int N=200010; typedef long long ll;
#define int ll
signed main(){
	int T; cin>>T;
	while(T--){
		int n; cin>>n;
		#define p(n) (1ll<<(n)) 
		cout<<(p(n/2+1)-2)<<endl;
	}
	return 0;
}

B. Phoenix and Beauty

显然要我们弄出一个周期为 \(k\) 个序列

如果数字种类数大于 \(k\) 那一定无解,除此之外,输出 \(nk\) 个数,每 \(k\) 个数一周期,同时该序列要包含原序列的所有数就行了

#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
const int N=200010; typedef long long ll; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;}
#define int ll
set<int> s;
void solve(){
	int n,k,x; cin>>n>>k; s.clear();
	repeat(i,0,n)cin>>x,s.insert(x);
	if((int)s.size()>k){cout<<-1<<endl; return;}
	for(int i=1;(int)s.size()<k;i++)s.insert(i);
	cout<<n*k<<endl;
	repeat(i,0,n)
	for(auto j:s)
		cout<<j<<' ';
	cout<<endl;
}
signed main(){
	int T; cin>>T;
	while(T--)solve();
	return 0;
}

C. Phoenix and Distribution

好难啊

先对读入的字符串 \(s\) 排个序,然后分情况讨论

首先如果最小的字符的个数凑不齐 \(k\) 个,那输出第 \(k\) 个字符(比如说,s="aaxxzz",k=4,显然输出 "x" 就行了,比 "x" 小的字符串一定包含 'a' 但是又不可能)

(更:原来写的时候删了一个判断条件,结果发现假了,这里要特判一下 \(n=k\) 的情况qwq)

然后就是重点,我们有两种不同的方法,第一种方法是将答案均摊(第一个字符放第一个,第二个字符放第二个,第 \(k+1\) 个字符又放回第一个,依次类推),第二种方法是把前 \(k-1\) 个字符放前 \(k-1\) 个桶里,剩下的塞到最后一个桶

这两种方法取个max当然再好不过,我用了比较蠢的判定方法,如果先有 \(k\) 个相同的字符,剩下的 \(n-k\) 个字符也都相同(前 \(k\) 个字符 \(=A\),后 \(n-k\) 个字符 \(=B\),当然 \(A=B\) 也没事),这时候一定要均摊方法,其他情况用第二种方法

#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
const int N=200010; typedef long long ll; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;}
#define int ll
string s;
void solve(){
	int n,k; cin>>n>>k;
	cin>>s; sort(s.begin(),s.end());
	if(s[k-1]!=s[0] || n==k){
		putchar(s[k-1]);
		puts("");
		return;
	}
	if(s[n-1]==s[k]){
		putchar(s[0]);
		repeat(i,0,(n-1)/k)
			putchar(s[k]);
		puts("");
		return;
	}
	puts(s.c_str()+k-1);
}
signed main(){
	int T; cin>>T;
	while(T--)solve();
	return 0;
}

D. Phoenix and Science

一波操作后,发现其实要我们求一个最短的单调不减序列,这个序列的第一个数是 \(1\),任意相邻的两个数,后一个不能超过前一个的两倍,并且序列所有数之和为 \(n\)(解释一下,序列的第i个数表示第i天的细胞数)

初步思考可以发现,细胞数要以最快速度增长(指数增长),即 \(1,2,4,8...\),如果发现数字之和即将大于 \(n\) 就要减缓。但是这么写有点麻烦,一个简单的方法是生成一个长度为 \(sz\) 的序列 \(a[i]\),前 \(sz-1\) 个数满足指数增长,最后一个数等于 \(n-\sum\limits_{i=1}^{sz-1}a[i]\),如果 \(a[sz]<a[sz-1]\)(不符合要求)就要平均一下这两个数,这一步的代码表示为

if(a[sz-1]<a[sz-2]){
	int sum=a[sz-1]+a[sz-2];
	a[sz-2]=sum/2;
	a[sz-1]=(sum+1)/2;
}

然后输出 \(sz-1\)\(a[i]\) 的差分数组即可

#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
const int N=200010; typedef long long ll; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;}
#define int ll
vector<int> a;
void solve(){
	int n; cin>>n; a.clear();
	for(int i=1;;i<<=1){
		if(n<=i){a.push_back(n); break;}
		a.push_back(i);
		n-=i;
	}
	int sz=a.size();
	if(a[sz-1]<a[sz-2]){
		int sum=a[sz-1]+a[sz-2];
		a[sz-2]=sum/2;
		a[sz-1]=(sum+1)/2;
	}
	cout<<sz-1<<endl;
	repeat(i,0,sz-1)
		cout<<a[i+1]-a[i]<<' ';
	cout<<endl;
}
signed main(){
	int T; cin>>T;
	while(T--)solve();
	return 0;
}

E. Phoenix and Berries

假设同色的浆果才能放入同一篮子中,那么答案显然是 \(\lfloor\dfrac{\sum a[i]}k\rfloor+\lfloor\dfrac{\sum b[i]}k\rfloor\)

如果同树的浆果也能放同一篮子呢?

智熄地思考后发现,由于 \(n,k\) 很小,甚至可以用优化后的 \(O(n^3)\) 算法(不优化其实也行),而题目又和(模 \(k\) 数)很有关系,我们考虑在模 \(k\) 的意义上背包dp(就是如果只考虑同树的浆果放篮子里,那么我们要dp出成功摘下的第一种颜色的浆果个数模k的数的所有可能)

dp每个状态只有01两种可能,显然能用bitset优化,复杂度除以32,美滋滋

emmm太难讲了,咕了,等会再说

#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
const int N=510; typedef long long ll; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;}
#define int ll
int a[N],b[N],k;
bitset<N*2> dp,dp2;
void push(int l,int r){
	if(l>r)return;
	dp2=0;
	repeat(i,l,r+1)
		dp2|=dp<<i;
	dp|=dp2;
	dp|=dp>>k;
}
void solve(){
	int n,sa=0,sb=0,ans=0;
	cin>>n>>k;
	repeat(i,0,n)cin>>a[i]>>b[i],sa+=a[i],sb+=b[i];
	dp=1;
	repeat(i,0,n){
		push(max(1ll,k-b[i]),min(k-1,a[i]));
	}
	ans=sa/k+sb/k;
	repeat(i,0,k+1)
	if(dp[i]){
		int j=k-i;
		if(sa>=i && sb>=j)
			ans=max(ans,(sa-i)/k+(sb-j)/k+1);
	}
	cout<<ans<<endl;
}
signed main(){
	int T=1; //cin>>T;
	while(T--)solve();
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/axiomofchoice/p/12815604.html