专栏文章

题解:P13617 [ICPC 2024 APC] Bit Counting Sequence

P13617题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minqd83y
此快照首次捕获于
2025/12/02 06:38
3 个月前
此快照最后确认于
2025/12/02 06:38
3 个月前
查看原文

思路

不难发现,其实 pp 函数就是 popcount\text{popcount},虽然没有什么意义。楼下很多大佬都直接看出性质了,由于本人太菜,所以给一个特别中规中矩的方法。
与别的方法不同,这个方法从 aa 数组最后往最前遍历。
最开始也就是在 ana_n 的时候,最优答案一定是 2an12^{a_n}-1。 对于 a1a_1an1a_{n-1} 的情况,有几种可能:
  1. 如果 aia_i00,上一位答案为 11 则可以减,否则无解。
  2. 如果 ai+1ai>1a_{i+1}-a_i>1,显然无解。因为发生进位 11 的个数是不增的,而不发生进位 11 的个数只能加 11
  3. 如果 ai+1ai=1a_{i+1}-a_i=1,答案的最低二进制位一定为 11,我们直接看答案能不能减 11 即可。
  4. 如果 ai+1ai0a_{i+1}-a_i \le 0,一定发生了进位,且进位之后答案末尾只有 aiai+1+1a_i-a_{i+1}+100。我们只需在答案最末尾补齐 00 然后看能不能减 11 即可。
最后非常重要的:从头到位扫一遍,看看可不可以满足整个序列。
引用机房神犇 gaozeju 的话讲:检查满不满足原因就是假定序列是合法的,但是序列有可能不合法。

代码

CPP
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N(5e5+5);
int T,n,a[N];
ll ans;
inline int getpos(ll x){
	for(int d(0);x;){
		if(x&1)return d;
		x>>=1;
		++d;
	}return -1;
}
inline int cnt(ll x){
	int res(0);
	for(;x;x>>=1){
		if(x&1)++res;
	}return res;
}
inline void solve(){
	cin>>n;
	for(int i(1);i<=n;++i)cin>>a[i];
	ans=1;ans<<=a[n];--ans;
	for(int i(n-1);i>=1;--i){
		if(a[i]==0){
			if(ans==1)--ans;
			else{cout<<-1<<'\n';return ;}
		}else if(a[i+1]-a[i]>1){cout<<-1<<'\n';return ;}
		else if(a[i+1]-a[i]==1){
			if(ans>=1)--ans;
			else{cout<<-1<<'\n';return ;}
		}else{
			int pos=getpos(ans),chg=a[i]-a[i+1]+1;
			if(pos==-1){cout<<-1<<'\n';return ;}
			if(pos>chg){cout<<-1<<'\n';return ;}
			ans<<=(chg-pos);
			if(ans-1>=0)--ans;
			else{cout<<-1<<'\n';return ;}
		}
	}ll tmp=ans;
	for(int i(1);i<=n;++i){
		if(cnt(tmp)==a[i])++tmp;
		else{cout<<-1<<'\n';return ;}
	}cout<<ans<<'\n';
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>T;
	for(;T;--T)solve();
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...