Codeforces Round958 (div2) A~C

A. Split the Multiset

题意:给定一个数,可以进行若干次操作,每次可以将它拆分成不超过k个数,问最少多少次操作可以将该数全部拆为1。

思路:找规律,可以发现每次将最大的数S拆为k-1个1和1个S-(k-1)直到最大的数S为1即可,代码如下:

void solve(){
	int n,k;
	cin >> n >> k;
	int ans = 0;
	while(n > 1){
		n -= (k-1);
		ans+=1;
	}
	cout << ans << endl;
}

B. Make Majority

题意:给定一个01序列,进行若干次操作,每次操作可以指定任意一个区间的数变为该区间内出现最多的数,问最终能否将该序列变为只包含一个1。

思路:先把所有连续的0合并为一个0,最后判断0和1的数量即可。代码如下:

void solve(){
	int zero = 0,one = 0;
	int n;
	cin >> n;
	bool last = false;
	for(int i = 1;i<=n;i++){
		char c;
		cin >> c;
		int num;
		num = c - '0';
		if(num == 0){
			last = true;
		}if(num != 0 and last){
			last = false;
			zero++;
			one++;
		}else if(num != 0){
			one++;
		}
	}
	if(last)
		zero++;
	if(zero >= one)
		cout << "NO" << endl;
	else
		cout << "YES" << endl;
}

C. Increasing Sequence with Fixed OR

题意:给定一个正整数n,求一个序列a,a中元素满足a[i] | a[i-1] = n , 并且a序列递增,求该序列最大长度并输出。

思路:找规律,要使得两两或运算结果都为n,并且递增,我们可以将n转为二进制,该二进制包含多少个1的数量+1即为该序列最大长度,然后从该二进制最高位开始,往前忽略一个二进制位的1输出它的值即可,代码如下:

void solve(){
	int n;
	int a[70];
	bool vis[70];
	cin >> n;
	int k = 0;
	int maxN;
	for(int i = 0;i<=63;i++){
		if(n >> i & 1){
			a[i] = 1;
			k++;
			maxN = i;
			vis[i] = true;
		}else{
			a[i] = false;
			vis[i] = false;
		}
	}
	
	if(k == 1){
		cout << 1 << endl << n << endl;
		return;
	}
	cout << k+1 << endl;
	for(int i = 1;i<=k+1;i++){
		bool ok = true;
		int num = 0;
		for(int j = maxN;j>=0;j--){
			if(vis[j] and ok and i != k+1){
				vis[j] = false;
				ok = false;
				continue;
			}
			if(a[j] == 1){
				num += fastPower(2,j);
			}
		}
		cout << num << " ";
	}
	cout << endl;
}

优化:快速幂,代码如下:

int fastPower(int num, int power) {
    int result = 1;
    while (power > 0) {
        if (power & 1) {	//if(power%2==1)
            result = result * num;//result = result * num%mod
        }
        power >>= 1; //power=power/2
        num = (num * num);//num = (num * num)%mod
    }
    return result;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值