题目链接:https://atcoder.jp/contests/aising2020/tasks/aising2020_d
题目大意:给一个长度为n的01串,对于i位置进行反转(0转1,1转0);
f(x): x转换成2进制时1的个数y,x=x%y,当x==0时循环的次数。
求解i(0~n-1)将i反转后01串转换成10进制x,求f(x)的值。
思路:01串总长度为2e5,故能想到取一次%mod后这个值一定在2e5范围内。然后就可以暴力求得结果了。问题是怎么去取第一次mod呢?首先我们预处理1的个数为one,从高位逐步*2+该位的值%mod。显然每次处理情况是one+1或者one-1,所以mod等于one-1或者one+1,因为要重复计算,所以首先把整体计算出来,后面只需要-2i或者+2i。
注意点:1.在计算过程中有个大坑就是1的个数会变成0的情况这个需要特判。
2.快速幂要开long long。
然后我们可以愉快的ac了。(细节看代码)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+100;
ll qpow(ll x,ll n,int mod)
{
ll sum=1;
while(n){
if(n&1) sum=sum*x%mod;
x=x*x%mod;
n>>=1;
}
return sum;
}
int ans(int x)
{
if(x==0) return 0;
int kk=__builtin_popcount(x);
return 1+ans(x%kk);
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);
int n;cin>>n;
string s;cin>>s;
int one=0;
for(int i=0;i<n;i++){
if(s[i]=='1') one++;
}
int p1=0,p2=0;
for(int i=0;i<n;i++){
if(one!=1){
p1=(p1*2+s[i]-'0')%(one-1);
}
p2=(p2*2+s[i]-'0')%(one+1);
}
for(int i=0;i<n;i++){
if((s[i]=='1'&&one==1)){
cout<<0<<endl;
}
else if(s[i]=='1'){
cout<<1+ans((p1-qpow(2,n-i-1,one-1)+(one-1))%(one-1))<<endl;
}
else if(s[i]=='0'){
cout<<1+ans((p2+qpow(2,n-i-1,one+1)+(one+1))%(one+1))<<endl;
}
}
return 0;
}
欢迎大家来指错。
本文解析AtCoder竞赛中一道关于01串处理的问题,通过预处理1的数量并使用快速幂技巧,实现了对特定操作下01串转换成十进制后的循环计数求解。
318

被折叠的 条评论
为什么被折叠?



