Codeforces Global Round 1

ACM题集:https://blog.csdn.net/weixin_39778570/article/details/83187443
题目链接:https://codeforces.com/contest/1110

A Parity

奇偶判断

B Tape

有1到m 有n个区间点 
使用不超过k个木板,覆盖所有点,要求木板最短
-------------------------------------------
对间隔排序,去掉间隔大的间隔
#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
ll n,m,k,a[100005],b[100005];
int main(){
	cin>>n>>m>>k;
	fo(i,1,n)scanf("%d",&a[i]);
	fo(i,1,n-1)b[i]=a[i+1]-a[i]-1; // 间隔 
	int ans = a[n]-a[1]+1;
	sort(b+1,b+n);
	for(int i=0; i<k-1 && n-1-i>0; i++){
		ans -= b[n-1-i]; 
	}
	cout<<ans<<endl;
	return 0;
}

C Meaningless Operations

给一堆数,这两种情况是合法序列[x,x,x],[x,x+1,x+2]
问最多有多少个这玩意
-------------------------------------------------
对于每个数 i, 他有[i,i,i]和 [i-1,i,i+1], [i,i+1,i+2]与下一个点 i+1有联系
所以  f[i][j][k] 表示 第i个数,状态t1[i-1,i,i+1]有j个,t2[i,i+1,i+2]有k个
t0 = [i-2,i-1,i]有L 个 
f[i][t1][t2] = max(f[i-1][t0][t1] + L +(num[i]-j-k-l)/3, f[i][t1][t2])
由于   (num[i]-j-k-l)%3 只有3种结果,所以舍弃的结果数只有3种
所以 j,k,l 的枚举范围为0到2 即可 
#include<bits/stdc++.h>
#define ll long long 
#define fo(i,j,n) for(register int i=j; i<=n; ++i) 
using namespace std;
const int maxn = 1000005;
int n,m,a[maxn];
int f[maxn][3][3];
void solve(){
	fo(i,1,m){
		fo(j,0,2){
			fo(k,0,2){
				// 影响第i个点的横放状态有两个,为i-1个点的
				// [i-2,i-1,i],[i-1,i,i+1]
				fo(l,0,2){
					if(a[i]<j+k+l)continue; 
					// 横放[i,i+1,i+2],加竖放 
					f[i][j][k] = max(f[i][j][k], f[i-1][l][j] + k + (a[i]-j-k-l)/3);
				} 
			}
		}
	} 
	cout<<f[m][0][0];
}
int main(){
	scanf("%d%d",&n,&m);
	fo(i,1,n){
		int x;scanf("%d",&x);
		a[x]++;
	}
	solve();
	return 0;
}

D Jongmah

给定数 a ,找出一个数 0<=b<n 
使得 ans = gcd( a^b, a&b) 最大,求ans
------------------------------------------
令 2^x <= a, 
当 2^x-1 != a时
令 b = 2^x-1 ^ a 则 a^b = 2^x-1, a&b=0
gcd(a^b,a&b) = gcd(2^x-1, 0) = 2^x-1 最大 

当 2^x-1 == a时
gcd(2^x-1 ^ b, b) =====> gcd( 2^x-1 - b, b)
====> gcd(2^x-1, b)   因为 gcd(x+y,y) ==> gcd(x,y)
所以我们只要找到最大的能整除的就行
#include<bits/stdc++.h>
#define ll long long 
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
ll q,n;
void solve(){
	ll x=1;
	while(x<=n){
		x<<=1;
	}
	x--;
	if(x==n){
		// gcd(2^x-1 ^ b, b) =====> gcd( 2^x-1 - b, b)
		// ====> gcd(2^x-1, b)   因为 gcd(x+y,y) ==> gcd(x,y)
		// 所以我们只要找到最大的能整除的就行 
		for(int i=2; i*i<=n; i++){
			if(n%i==0){
				printf("%lld\n",n/i);
				return;
			}
		}
		printf("%lld\n",1ll);
	}else{
		// b = 2^x-1 ^ a ====> a^b = 2^x-1
		// a&b = 0
		// gcd(a^b, a&b) = gcd(2^x-1, 0) = 2^x-1;
		printf("%lld\n",x);
	}
}
int main(){
	scanf("%lld",&q);
	while(q--){
		scanf("%lld",&n);
		solve();
	}
	return 0;
} 

E Magic Stones

E题目:
给定数组c[],对于c[i]可改变为 c[i+1]+c[i-1]-c[i]
问数组c,能否变成数组s
------------------------------------------------- 
差分数组 d[i] = c[i]-c[i-1],d[1] = c[1] 
c'[i] = c[i-1] + c[i+1] -c[i]
改变之后,差分数组变为
d'[i]   = c[i-1] + c[i+1] - c[i] - c[i-1] = c[i+1] - c[i] = d[i+1]
d'[i+1] = c[i+1] -(c[i-1] + c[i+1] - c[i])= c[i] - c[i-1] = d[i]
也就是改变c[i]之后,差分数组做了交换,其他不变
所以我们只要排序后,查看两个差分数组是否相同即可
即首项和之后的变化项都相同
---------------------------------------------------------
题外:
差分数组描述一组数组的变换关系,只要首项一样,其他变换关系一样,则说明完全一样
差分数组d的前缀和 f 为 原数组
如果要修该原数组a,可修改差分数组d,然后d的前缀和f,即为新的所求数组
f的前缀和sum即为修改后的a的前缀和 
#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
int n,a1[100005],a2[100005],d1[100005],d2[100005]; 
int main(){
	scanf("%d",&n);
	fo(i,1,n)scanf("%d",&a1[i]);
	fo(i,1,n)scanf("%d",&a2[i]);
	d1[1]=a1[1],d2[1]=a2[1];
	fo(i,2,n)d1[i] = a1[i]-a1[i-1],d2[i] = a2[i]-a2[i-1];
	sort(d1+2,d1+1+n);
	sort(d2+2,d2+1+n);
	fo(i,1,n){
		if(d1[i]!=d2[i]){
			puts("No");
			return 0;
		}
	}
	puts("Yes");
	return 0;
}

F Nearest Leaf

用线段树维护,我不会

G Tree-Tac-Toe

H Modest Substrings

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 设计师:向前走别回头 返回首页