返回顶部

AtCoder AIsing Programming Contest 2020 D - Anything Goes to Zero (二进制,模拟)

  • 题意:给你一个长度为\(n\)\(01\)串,从高位到低位遍历,对该位取反,用得到的十进制数\(mod\)所有位上\(1\)的个数,不断循环直到为\(0\),输出每次遍历时循环的次数.

  • 题解:根据题意,我们可以直接模拟来写,但是所给数据范围会TLE,我们先记所有\(1\)的个数为\(sum\),当取模时,我们要么取\(sum+1\),要么取\(sum-1\).然后我们要算出字符串对应的十进制数,而因为数据过大,我们要取模,这里我们算两种取模情况下的总值(\(sum+1\)\(sum-1\)),然后再算某一位对应十进制的值(同样两种情况),用两个数组存下来,最后遍历的时候,我们直接暴力算:总值\(\pm\)(某一位)%(\(sum \pm 1\)).

  • 代码:

    int n;
    int sum;
    int add[N],sub[N];
    int val_add,val_sub;
    int ans;
    string s;
     
    int fpow(int x){
        int res=0;
        while(x){
          res++;
          x%=__builtin_popcount(x);
        }
        return res;
    }
    
    int main() {
        ios::sync_with_stdio(false);cin.tie(0);
        cin>>n>>s;
         for(int i=0;i<n;++i){
             if(s[i]=='1') sum++;
         }
         add[n-1]=1,sub[n-1]=1;
         for(int i=n-2;i>=0;--i){
             if(sum!=1) sub[i]=2*sub[i+1]%(sum-1);
             add[i]=2*add[i+1]%(sum+1);
         }
    
         for(int i=n-1;i>=0;--i){
            if(s[i]=='1'){
               if(sum!=1) val_sub=(val_sub+sub[i])%(sum-1);
               val_add=(val_add+add[i])%(sum+1);
            }
         }
    
         for(int i=0;i<n;++i){
            if(s[i]=='1'){
               if(sum==1){
                 cout<<0<<endl;
                 continue;
               }
               ans=(val_sub-sub[i])%(sum-1)+(sum-1);
               ans%=(sum-1);
               cout<<fpow(ans)+1<<endl;
            }
            else{
              ans=(val_add+add[i])%(sum+1)+sum+1;
              ans%=(sum+1);
              cout<<fpow(ans)+1<<endl;
            }
         }
    
        return 0;
    }
    
posted @ 2020-07-15 15:10  _Kolibri  阅读(135)  评论(0)    收藏  举报