Codeforces Round #636 (Div. 3)题解

Codeforces Round #636 (Div. 3)题解


比赛地址


A. Candies

利用等比数列求和得到等式 x ( 2 k − 1 ) = n x(2^k-1)=n x(2k1)=n x = n 2 k − 1 x=\frac{n}{2^k-1} x=2k1n,之后依次枚举k直到 ( 2 k − 1 ) ∣ n (2^k-1)|n (2k1)n,相除即得到答案x

#include
using namespace std;
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		int n;
		scanf("%d",&n);
		int k=2;
		while(1){
			long long kk=k*2-1;
			if(n%(kk)==0){
				printf("%d\n",n/kk);
				break;
			}
			k*=2;
		}
	}
	return 0;
}

B. Balanced Array

要求构造一个数字均不同的正数列,前 n / 2 n/2 n/2项为偶数,后 n / 2 n/2 n/2项为奇数,且偶数和与奇数和相等。当 n / 2 n/2 n/2为奇数时无解,因为奇数个偶数和为偶数,奇数个奇数和为奇数,所以两个和不可能相等。 n / 2 n/2 n/2为偶数时的思路:偶数直接放2,4,6,8…奇数放1,3,5,…最后一个奇数=偶数和-已放的奇数的和

#include
using namespace std;
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		int n;
		scanf("%d",&n);
		if((n/2)&1) printf("NO\n");
		else{
			long long sum1=0,sum2=0;
			printf("YES\n");
			for(int i=1;i<=n/2;i++){
				printf("%d ",i*2);
				sum1+=i*2;
			}
			for(int i=1;i<=n/2-1;i++){
				printf("%d ",i*2-1);
				sum2+=i*2-1;
			}
			printf("%lld\n",sum1-sum2);
		}
	}
	return 0;
}

C. Alternating Subsequence

称一段连续的同号的数为一个块,从左到右遍历这些块,每次取块的最大值即可

#include
using namespace std;
const int N=200005;
long long a[N];
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		int n;
		scanf("%d",&n);
		for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
		long long sum=0;
		long long maxx=-1e15;
		for(int i=1;i<=n;i++){
			bool ok=0;
			if((a[i]>=0&&a[i-1]>=0||a[i]<=0&&a[i-1]<=0)){
				maxx=max(maxx,a[i]);
			}
			else{
				ok=1;
				sum+=maxx;
				maxx=-1e15;
				maxx=max(maxx,a[i]);
			}
		
		}
		sum+=maxx;
		printf("%lld\n",sum);
		
	}
	return 0;
}

D. Constant Palindrome Sum

对于每一对数 a i a_i ai a n − i + 1 a_{n-i+1} ani+1,为了使 a i + a n − i + 1 = x a_i+a_{n-i+1}=x ai+ani+1=x,它的替换情况有三种:第一是两个数都被替换,第二是仅替换其中一个数,第三是不进行替换。对于每对数,我们可以算出最多进行一次替换的 x x x的范围,即 [ 1 + m i n { a i , a n − i + 1 } , k + m a x { a i , a n − i + 1 } ] [1+min\{a_i,a_{n-i+1}\},k+max\{a_i,a_{n-i+1}\}] [1+min{ai,ani+1},k+max{ai,ani+1}]也就是说当x的范围落在这个闭区间时,这对数最多只被替换一次,其中包括替换一次和不被替换的情况。我们再用 c n t x cnt_x cntx数组来记录和为 x x x的数对的数量。我们用 n u m x num_x numx记录当和为 x x x时,最多替换一次的总次数。那么对每对数进行处理时,就会发现这是个区间修改,单点查询的问题,但是查询只在最后进行一次查询,所以可以用差分的思想。令 p r e f x pref_x prefx记录 n u m x − n u m x − 1 num_x-num_{x-1} numxnumx1,则对 n u m num num的区间 [ l , r ] [l,r] [l,r]进行修改(每个+1)时,只需让 p r e f l 加 1 pref_l加1 prefl1 p r e f r + 1 减 1 pref_{r+1}减1 prefr+11即可。然后计算 n u m i = ∑ j = 1 i p r e f j num_i=\sum_{j=1}^ipref_j numi=j=1iprefj。最后计算答案,公式在代码中体现

#include
using namespace std;
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		int n,k;
		scanf("%d %d",&n,&k);
		vectora(n+5,0),cnt(2*k+5,0),pref(2*k+5,0);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		for(int i=1;i<=n/2;i++){
			cnt[a[i]+a[n-i+1]]++;
			int l1=1+a[i],r1=k+a[i];
			int l2=1+a[n-i+1],r2=k+a[n-i+1];
			pref[min(l1,l2)]++;
			pref[max(r1,r2)+1]--;
		}
		for(int i=2;i<=2*k;i++){
			pref[i]+=pref[i-1];
		}
		int ans=1e9;
		for(int i=2;i<=2*k;i++){
			ans=min(ans,pref[i]-cnt[i]+(n/2-pref[i])*2);
		}
		printf("%d\n",ans);
	}
	return 0;
}

E. Weights Distributing

路程可分为4段,a->x,x->b,b->x,x->c,可以发现{b,x}这段路走了两次,所以把最少的价格分配到这三条路上,其中{b,x}这段路分配最少的价格(中的最小价格)。通过3次BFS算出a,b,c到各个点的最短路,枚举交点 x x x,分配价格,记录下最小值即为答案。

#include
using namespace std;
const int INF=1e9;
vector >adj;
void bfs(vector&d,int s){
	d[s]=0;
	queueque;
	que.push(s);
	while(!que.empty()){
		int u=que.front();que.pop();
		for(int i=0;ip(m+1);
		for(int i=1;i<=m;i++) scanf("%d",&p[i]);
		sort(p.begin()+1,p.end());
		vectorpref(m+1,0);
		for(int i=1;i<=m;i++){
			pref[i]=pref[i-1]+p[i];
		}
//		for(int i=1;i<=m;i++) printf("%d\n",p[i]);
		adj=vector >(n+1);
		for(int i=1;i<=m;i++){
			int x,y;
			scanf("%d %d",&x,&y);
			adj[x].push_back(y);adj[y].push_back(x);
		}
		vectorda(n+1,INF),db(n+1,INF),dc(n+1,INF);
		bfs(da,a),bfs(db,b),bfs(dc,c);
		long long ans=1e18;
		for(int x=1;x<=n;x++){
			if(da[x]+db[x]+dc[x]>m) continue;
			ans=min(ans,pref[db[x]]+pref[da[x]+db[x]+dc[x]]);
		}
		printf("%lld\n",ans);
	}
	return 0;
}

F. Restore the Permutation by Sorted Segments

待补

第一次写题解,欢迎批评指正

你可能感兴趣的:(题解)